xref: /onnv-gate/usr/src/uts/sun4u/sunfire/io/simmstat.c (revision 11311:639e7bc0b42f)
11341Sstevel /*
21341Sstevel  * CDDL HEADER START
31341Sstevel  *
41341Sstevel  * The contents of this file are subject to the terms of the
51341Sstevel  * Common Development and Distribution License (the "License").
61341Sstevel  * You may not use this file except in compliance with the License.
71341Sstevel  *
81341Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91341Sstevel  * or http://www.opensolaris.org/os/licensing.
101341Sstevel  * See the License for the specific language governing permissions
111341Sstevel  * and limitations under the License.
121341Sstevel  *
131341Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141341Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151341Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161341Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171341Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181341Sstevel  *
191341Sstevel  * CDDL HEADER END
201341Sstevel  */
211341Sstevel 
221341Sstevel /*
23*11311SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241341Sstevel  * Use is subject to license terms.
251341Sstevel  */
261341Sstevel 
271341Sstevel 
281341Sstevel #include <sys/types.h>
291341Sstevel #include <sys/conf.h>
301341Sstevel #include <sys/ddi.h>
311341Sstevel #include <sys/sunddi.h>
321341Sstevel #include <sys/ddi_impldefs.h>
331341Sstevel #include <sys/obpdefs.h>
341341Sstevel #include <sys/cmn_err.h>
351341Sstevel #include <sys/errno.h>
361341Sstevel #include <sys/kmem.h>
371341Sstevel #include <sys/debug.h>
381341Sstevel #include <sys/sysmacros.h>
391341Sstevel #include <sys/ivintr.h>
401341Sstevel #include <sys/intr.h>
411341Sstevel #include <sys/intreg.h>
421341Sstevel #include <sys/autoconf.h>
431341Sstevel #include <sys/modctl.h>
441341Sstevel #include <sys/spl.h>
451341Sstevel 
461341Sstevel #include <sys/fhc.h>
471341Sstevel #include <sys/simmstat.h>
481341Sstevel 
491341Sstevel /* Useful debugging Stuff */
501341Sstevel #include <sys/nexusdebug.h>
511341Sstevel 
521341Sstevel /*
531341Sstevel  * Function prototypes
541341Sstevel  */
551341Sstevel 
561341Sstevel static int simmstat_attach(dev_info_t *, ddi_attach_cmd_t);
571341Sstevel 
581341Sstevel static int simmstat_detach(dev_info_t *, ddi_detach_cmd_t);
591341Sstevel 
601341Sstevel static void simmstat_add_kstats(struct simmstat_soft_state *);
611341Sstevel 
621341Sstevel static int simmstat_kstat_update(kstat_t *, int);
631341Sstevel 
641341Sstevel /*
651341Sstevel  * Configuration data structures
661341Sstevel  */
671341Sstevel static struct cb_ops simmstat_cb_ops = {
681341Sstevel 	nulldev,			/* open */
691341Sstevel 	nulldev,			/* close */
701341Sstevel 	nulldev,			/* strategy */
711341Sstevel 	nulldev,			/* print */
721341Sstevel 	nodev,				/* dump */
731341Sstevel 	nulldev,			/* read */
741341Sstevel 	nulldev,			/* write */
751341Sstevel 	nulldev,			/* ioctl */
761341Sstevel 	nodev,				/* devmap */
771341Sstevel 	nodev,				/* mmap */
781341Sstevel 	nodev,				/* segmap */
791341Sstevel 	nochpoll,			/* poll */
801341Sstevel 	ddi_prop_op,			/* cb_prop_op */
811341Sstevel 	0,				/* streamtab */
821341Sstevel 	D_MP | D_NEW | D_HOTPLUG,	/* Driver compatibility flag */
831341Sstevel 	CB_REV,				/* rev */
841341Sstevel 	nodev,				/* cb_aread */
851341Sstevel 	nodev				/* cb_awrite */
861341Sstevel };
871341Sstevel 
881341Sstevel static struct dev_ops simmstat_ops = {
891341Sstevel 	DEVO_REV,			/* rev */
901341Sstevel 	0,				/* refcnt  */
911341Sstevel 	ddi_no_info,			/* getinfo */
921341Sstevel 	nulldev,			/* identify */
931341Sstevel 	nulldev,			/* probe */
941341Sstevel 	simmstat_attach,		/* attach */
951341Sstevel 	simmstat_detach,		/* detach */
961341Sstevel 	nulldev,			/* reset */
971341Sstevel 	&simmstat_cb_ops,		/* cb_ops */
981341Sstevel 	(struct bus_ops *)0,		/* bus_ops */
997656SSherry.Moore@Sun.COM 	nulldev,			/* power */
1007656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,			/* quiesce */
1011341Sstevel };
1021341Sstevel 
1031341Sstevel static uint_t simmstat_reg_read_delay_us = 10;
1041341Sstevel 
1051341Sstevel /*
1061341Sstevel  * Driver globals
1071341Sstevel  */
1081341Sstevel void *simmstatp;
1091341Sstevel 
1101341Sstevel extern struct mod_ops mod_driverops;
1111341Sstevel 
1121341Sstevel static struct modldrv modldrv = {
1131341Sstevel 	&mod_driverops,			/* module type, this one is a driver */
1147656SSherry.Moore@Sun.COM 	"SIMM-status Leaf",		/* module name */
1151341Sstevel 	&simmstat_ops,			/* driver ops */
1161341Sstevel };
1171341Sstevel 
1181341Sstevel static struct modlinkage modlinkage = {
1191341Sstevel 	MODREV_1,		/* rev */
1201341Sstevel 	(void *)&modldrv,
1211341Sstevel 	NULL
1221341Sstevel };
1231341Sstevel 
1241341Sstevel #ifndef	lint
1251366Spetede char _depends_on[] = "drv/fhc";
1261341Sstevel #endif	/* lint */
1271341Sstevel 
1281341Sstevel /*
1291341Sstevel  * These are the module initialization routines.
1301341Sstevel  */
1311341Sstevel 
1321341Sstevel int
_init(void)1331341Sstevel _init(void)
1341341Sstevel {
1351341Sstevel 	int error;
1361341Sstevel 
1371341Sstevel 	if ((error = ddi_soft_state_init(&simmstatp,
1381341Sstevel 	    sizeof (struct simmstat_soft_state), 1)) != 0)
1391341Sstevel 		return (error);
1401341Sstevel 
1411341Sstevel 	return (mod_install(&modlinkage));
1421341Sstevel }
1431341Sstevel 
1441341Sstevel int
_fini(void)1451341Sstevel _fini(void)
1461341Sstevel {
1471341Sstevel 	int error;
1481341Sstevel 
1491341Sstevel 	if ((error = mod_remove(&modlinkage)) != 0)
1501341Sstevel 		return (error);
1511341Sstevel 
1521341Sstevel 	ddi_soft_state_fini(&simmstatp);
1531341Sstevel 	return (0);
1541341Sstevel }
1551341Sstevel 
1561341Sstevel int
_info(struct modinfo * modinfop)1571341Sstevel _info(struct modinfo *modinfop)
1581341Sstevel {
1591341Sstevel 	return (mod_info(&modlinkage, modinfop));
1601341Sstevel }
1611341Sstevel 
1621341Sstevel static int
simmstat_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)1631341Sstevel simmstat_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
1641341Sstevel {
1651341Sstevel 	struct simmstat_soft_state *softsp;
1661341Sstevel 	int instance;
1671341Sstevel 
1681341Sstevel 	switch (cmd) {
1691341Sstevel 	case DDI_ATTACH:
1701341Sstevel 		break;
1711341Sstevel 
1721341Sstevel 	case DDI_RESUME:
1731341Sstevel 		return (DDI_SUCCESS);
1741341Sstevel 
1751341Sstevel 	default:
1761341Sstevel 		return (DDI_FAILURE);
1771341Sstevel 	}
1781341Sstevel 
1791341Sstevel 	instance = ddi_get_instance(devi);
1801341Sstevel 
1811341Sstevel 	if (ddi_soft_state_zalloc(simmstatp, instance) != DDI_SUCCESS)
1821341Sstevel 		return (DDI_FAILURE);
1831341Sstevel 
1841341Sstevel 	softsp = ddi_get_soft_state(simmstatp, instance);
1851341Sstevel 
1861341Sstevel 	/* Set the dip in the soft state */
1871341Sstevel 	softsp->dip = devi;
1881341Sstevel 
1891341Sstevel 	/* Get the board number from this nodes parent device. */
1901341Sstevel 	softsp->pdip = ddi_get_parent(softsp->dip);
1911341Sstevel 	if ((softsp->board = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->pdip,
1921341Sstevel 	    DDI_PROP_DONTPASS, OBP_BOARDNUM, -1)) == -1) {
1931341Sstevel 		cmn_err(CE_WARN, "simmstat%d: unable to retrieve %s property",
1947656SSherry.Moore@Sun.COM 		    instance, OBP_BOARDNUM);
1951341Sstevel 		goto bad;
1961341Sstevel 	}
1971341Sstevel 
1981341Sstevel 	DPRINTF(SIMMSTAT_ATTACH_DEBUG, ("simmstat%d: devi= 0x%p\n, "
199*11311SSurya.Prakki@Sun.COM 	    " softsp=0x%p\n", instance, (void *)devi, (void *)softsp));
2001341Sstevel 
2011341Sstevel 	/* map in the registers for this device. */
2021341Sstevel 	if (ddi_map_regs(softsp->dip, 0,
2031341Sstevel 	    (caddr_t *)&softsp->simmstat_base, 0, 0)) {
2041341Sstevel 		cmn_err(CE_WARN, "simmstat%d: unable to map registers",
2057656SSherry.Moore@Sun.COM 		    instance);
2061341Sstevel 		goto bad;
2071341Sstevel 	}
2081341Sstevel 
2091341Sstevel 	/* nothing to suspend/resume here */
2101341Sstevel 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
2117656SSherry.Moore@Sun.COM 	    "pm-hardware-state", "no-suspend-resume");
2121341Sstevel 
2131341Sstevel 	/* create the kstats for this device */
2141341Sstevel 	simmstat_add_kstats(softsp);
2151341Sstevel 
2161341Sstevel 	ddi_report_dev(devi);
2171341Sstevel 
2181341Sstevel 	return (DDI_SUCCESS);
2191341Sstevel 
2201341Sstevel bad:
2211341Sstevel 	ddi_soft_state_free(simmstatp, instance);
2221341Sstevel 	return (DDI_FAILURE);
2231341Sstevel }
2241341Sstevel 
2251341Sstevel /* ARGSUSED */
2261341Sstevel static int
simmstat_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)2271341Sstevel simmstat_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
2281341Sstevel {
2291341Sstevel 	int instance;
2301341Sstevel 	struct simmstat_soft_state *softsp;
2311341Sstevel 
2321341Sstevel 	/* get the instance of this devi */
2331341Sstevel 	instance = ddi_get_instance(devi);
2341341Sstevel 
2351341Sstevel 	/* get the soft state pointer for this device node */
2361341Sstevel 	softsp = ddi_get_soft_state(simmstatp, instance);
2371341Sstevel 
2381341Sstevel 	switch (cmd) {
2391341Sstevel 	case DDI_SUSPEND:
2401341Sstevel 		return (DDI_SUCCESS);
2411341Sstevel 
2421341Sstevel 	case DDI_DETACH:
2431341Sstevel 		(void) fhc_bdlist_lock(softsp->board);
2441341Sstevel 		if (fhc_bd_detachable(softsp->board))
2451341Sstevel 			break;
2461341Sstevel 		else
2471341Sstevel 			fhc_bdlist_unlock();
2481341Sstevel 		/* FALLTHROUGH */
2491341Sstevel 
2501341Sstevel 	default:
2511341Sstevel 		return (DDI_FAILURE);
2521341Sstevel 	}
2531341Sstevel 
2541341Sstevel 	fhc_bdlist_unlock();
2551341Sstevel 
2561341Sstevel 	/* remove the kstat for this board */
2571341Sstevel 	kstat_delete(softsp->simmstat_ksp);
2581341Sstevel 
2591341Sstevel 	/* unmap the registers */
2601341Sstevel 	ddi_unmap_regs(softsp->dip, 0,
2617656SSherry.Moore@Sun.COM 	    (caddr_t *)&softsp->simmstat_base, 0, 0);
2621341Sstevel 
2631341Sstevel 	/* free up the soft state */
2641341Sstevel 	ddi_soft_state_free(simmstatp, instance);
2651341Sstevel 	ddi_prop_remove_all(devi);
2661341Sstevel 
2671341Sstevel 	return (DDI_SUCCESS);
2681341Sstevel }
2691341Sstevel 
2701341Sstevel static void
simmstat_add_kstats(struct simmstat_soft_state * softsp)2711341Sstevel simmstat_add_kstats(struct simmstat_soft_state *softsp)
2721341Sstevel {
2731341Sstevel 	struct kstat *simmstat_ksp;
2741341Sstevel 
2751341Sstevel 	if ((simmstat_ksp = kstat_create("unix", softsp->board,
2761341Sstevel 	    SIMMSTAT_KSTAT_NAME, "misc", KSTAT_TYPE_RAW,
2771341Sstevel 	    SIMM_COUNT, KSTAT_FLAG_PERSISTENT)) == NULL) {
2781341Sstevel 		cmn_err(CE_WARN, "simmstat%d: kstat_create failed",
2797656SSherry.Moore@Sun.COM 		    ddi_get_instance(softsp->dip));
2801341Sstevel 	}
2811341Sstevel 
2821341Sstevel 	simmstat_ksp->ks_update = simmstat_kstat_update;
2831341Sstevel 	simmstat_ksp->ks_private = (void *)softsp;
2841341Sstevel 	softsp->simmstat_ksp = simmstat_ksp;
2851341Sstevel 	kstat_install(simmstat_ksp);
2861341Sstevel }
2871341Sstevel 
2881341Sstevel /*
2891341Sstevel  * Kstats only need ks_update functions when they change dynamically
2901341Sstevel  * at run time.
2911341Sstevel  * In the case of the simmstat registers, they contain battery
2921341Sstevel  * information for NVSIMMs. These need to be updated whenever a
2931341Sstevel  * kstat_read asks for the data. There is currently no plan to
2941341Sstevel  * ship NVSIMMs on this platform, but this support must be present.
2951341Sstevel  */
2961341Sstevel 
2971341Sstevel static int
simmstat_kstat_update(kstat_t * ksp,int rw)2981341Sstevel simmstat_kstat_update(kstat_t *ksp, int rw)
2991341Sstevel {
3001341Sstevel 	struct simmstat_soft_state *softsp;
3011341Sstevel 	volatile char *statp;	/* pointer to hardware register */
3021341Sstevel 	char *kstatp;		/* pointer to kstat data buffer */
3031341Sstevel 	int i;
3041341Sstevel 
3051341Sstevel 	kstatp = (char *)ksp->ks_data;
3061341Sstevel 	softsp = (struct simmstat_soft_state *)ksp->ks_private;
3071341Sstevel 
3081341Sstevel 	statp = (char *)softsp->simmstat_base;
3091341Sstevel 
3101341Sstevel 	/* this is a read-only kstat. Bail out on a write */
3111341Sstevel 	if (rw == KSTAT_WRITE) {
3121341Sstevel 		return (EACCES);
3131341Sstevel 	} else {
3141341Sstevel 
3151341Sstevel 		/*
3161341Sstevel 		 * copy current status of hardware into the kstat
3171341Sstevel 		 * structure.
3181341Sstevel 		 */
3191341Sstevel 		for (i = 0; i < SIMM_COUNT; i++, statp++, kstatp++) {
3201341Sstevel 			*kstatp = *statp;
3211341Sstevel 			DELAY(simmstat_reg_read_delay_us);
3221341Sstevel 		}
3231341Sstevel 	}
3241341Sstevel 	return (0);
3251341Sstevel }
326