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