xref: /onnv-gate/usr/src/uts/sun4u/sunfire/io/sram.c (revision 11311:639e7bc0b42f)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
51708Sstevel  * Common Development and Distribution License (the "License").
61708Sstevel  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel 
221708Sstevel /*
23*11311SSurya.Prakki@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241708Sstevel  * Use is subject to license terms.
251708Sstevel  */
261708Sstevel 
271708Sstevel 
281708Sstevel #include <sys/types.h>
291708Sstevel #include <sys/conf.h>
301708Sstevel #include <sys/ddi.h>
311708Sstevel #include <sys/sunddi.h>
321708Sstevel #include <sys/ddi_impldefs.h>
331708Sstevel #include <sys/obpdefs.h>
341708Sstevel #include <sys/cmn_err.h>
351708Sstevel #include <sys/errno.h>
361708Sstevel #include <sys/kmem.h>
371708Sstevel #include <sys/debug.h>
381708Sstevel #include <sys/sysmacros.h>
391708Sstevel #include <sys/autoconf.h>
401708Sstevel #include <sys/modctl.h>
411708Sstevel 
421708Sstevel #include <sys/fhc.h>
431708Sstevel #include <sys/sram.h>
441708Sstevel #include <sys/promif.h>
451708Sstevel 
461708Sstevel /* Useful debugging Stuff */
471708Sstevel #include <sys/nexusdebug.h>
481708Sstevel 
491708Sstevel /*
501708Sstevel  * Function protoypes
511708Sstevel  */
521708Sstevel 
531708Sstevel static int sram_attach(dev_info_t *, ddi_attach_cmd_t);
541708Sstevel 
551708Sstevel static int sram_detach(dev_info_t *, ddi_detach_cmd_t);
561708Sstevel 
571708Sstevel static void sram_add_kstats(struct sram_soft_state *);
581708Sstevel 
591708Sstevel /*
601708Sstevel  * Configuration data structures
611708Sstevel  */
621708Sstevel static struct cb_ops sram_cb_ops = {
631708Sstevel 	nulldev,			/* open */
641708Sstevel 	nulldev,			/* close */
651708Sstevel 	nulldev,			/* strategy */
661708Sstevel 	nulldev,			/* print */
671708Sstevel 	nodev,				/* dump */
681708Sstevel 	nulldev,			/* read */
691708Sstevel 	nulldev,			/* write */
701708Sstevel 	nulldev,			/* ioctl */
711708Sstevel 	nodev,				/* devmap */
721708Sstevel 	nodev,				/* mmap */
731708Sstevel 	nodev,				/* segmap */
741708Sstevel 	nochpoll,			/* poll */
751708Sstevel 	ddi_prop_op,			/* cb_prop_op */
761708Sstevel 	0,				/* streamtab */
771708Sstevel 	D_MP | D_NEW | D_HOTPLUG,	/* Driver compatibility flag */
781708Sstevel 	CB_REV,				/* rev */
791708Sstevel 	nodev,				/* cb_aread */
801708Sstevel 	nodev				/* cb_awrite */
811708Sstevel };
821708Sstevel 
831708Sstevel static struct dev_ops sram_ops = {
841708Sstevel 	DEVO_REV,			/* rev */
851708Sstevel 	0,				/* refcnt  */
861708Sstevel 	ddi_no_info,			/* getinfo */
871708Sstevel 	nulldev,			/* identify */
881708Sstevel 	nulldev,			/* probe */
891708Sstevel 	sram_attach,			/* attach */
901708Sstevel 	sram_detach,			/* detach */
911708Sstevel 	nulldev,			/* reset */
921708Sstevel 	&sram_cb_ops,			/* cb_ops */
931708Sstevel 	(struct bus_ops *)0,		/* bus_ops */
947656SSherry.Moore@Sun.COM 	nulldev,			/* power */
957656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,			/* quiesce */
961708Sstevel };
971708Sstevel 
981708Sstevel 
991708Sstevel /*
1001708Sstevel  * Driver globals
1011708Sstevel  */
1021708Sstevel void *sramp;			/* sram soft state hook */
1031708Sstevel static struct kstat *resetinfo_ksp = NULL;
1041708Sstevel static int reset_info_created = 0;
1051708Sstevel 
1061708Sstevel extern struct mod_ops mod_driverops;
1071708Sstevel 
1081708Sstevel static struct modldrv modldrv = {
1091708Sstevel 	&mod_driverops,		/* Type of module.  This one is a driver */
1107656SSherry.Moore@Sun.COM 	"Sram Leaf",		/* name of module */
1111708Sstevel 	&sram_ops,		/* driver ops */
1121708Sstevel };
1131708Sstevel 
1141708Sstevel static struct modlinkage modlinkage = {
1151708Sstevel 	MODREV_1,
1161708Sstevel 	(void *)&modldrv,
1171708Sstevel 	NULL
1181708Sstevel };
1191708Sstevel 
1201708Sstevel #ifndef	lint
1211708Sstevel char _depends_on[] = "drv/fhc";
1221708Sstevel #endif	/* lint */
1231708Sstevel 
1241708Sstevel /*
1251708Sstevel  * These are the module initialization routines.
1261708Sstevel  */
1271708Sstevel 
1281708Sstevel int
_init(void)1291708Sstevel _init(void)
1301708Sstevel {
1311708Sstevel 	int error;
1321708Sstevel 
1331708Sstevel 	if ((error = ddi_soft_state_init(&sramp,
1341708Sstevel 	    sizeof (struct sram_soft_state), 1)) == 0 &&
1351708Sstevel 	    (error = mod_install(&modlinkage)) != 0)
1361708Sstevel 		ddi_soft_state_fini(&sramp);
1371708Sstevel 	return (error);
1381708Sstevel }
1391708Sstevel 
1401708Sstevel int
_fini(void)1411708Sstevel _fini(void)
1421708Sstevel {
1431708Sstevel 	int error;
1441708Sstevel 
1451708Sstevel 	if ((error = mod_remove(&modlinkage)) == 0)
1461708Sstevel 		ddi_soft_state_fini(&sramp);
1471708Sstevel 	return (error);
1481708Sstevel }
1491708Sstevel 
1501708Sstevel int
_info(struct modinfo * modinfop)1511708Sstevel _info(struct modinfo *modinfop)
1521708Sstevel {
1531708Sstevel 	return (mod_info(&modlinkage, modinfop));
1541708Sstevel }
1551708Sstevel 
1561708Sstevel static int
sram_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)1571708Sstevel sram_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
1581708Sstevel {
1591708Sstevel 	int instance;
1601708Sstevel 	struct sram_soft_state *softsp;
1611708Sstevel 
1621708Sstevel 	switch (cmd) {
1631708Sstevel 	case DDI_ATTACH:
1641708Sstevel 		break;
1651708Sstevel 
1661708Sstevel 	case DDI_RESUME:
1671708Sstevel 		return (DDI_SUCCESS);
1681708Sstevel 
1691708Sstevel 	default:
1701708Sstevel 		return (DDI_FAILURE);
1711708Sstevel 	}
1721708Sstevel 
1731708Sstevel 	instance = ddi_get_instance(devi);
1741708Sstevel 
1751708Sstevel 	if (ddi_soft_state_zalloc(sramp, instance) != DDI_SUCCESS)
1761708Sstevel 		return (DDI_FAILURE);
1771708Sstevel 
1781708Sstevel 	softsp = ddi_get_soft_state(sramp, instance);
1791708Sstevel 
1801708Sstevel 	/* Set the dip in the soft state */
1811708Sstevel 	softsp->dip = devi;
1821708Sstevel 
1831708Sstevel 	/* get the board number from this devices parent. */
1841708Sstevel 	softsp->pdip = ddi_get_parent(softsp->dip);
1851708Sstevel 	if ((softsp->board = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->pdip,
1861708Sstevel 	    DDI_PROP_DONTPASS, OBP_BOARDNUM, -1)) == -1) {
1871708Sstevel 		cmn_err(CE_WARN, "sram%d: unable to retrieve %s property",
1887656SSherry.Moore@Sun.COM 		    instance, OBP_BOARDNUM);
1891708Sstevel 		goto bad;
1901708Sstevel 	}
1911708Sstevel 
1921708Sstevel 	DPRINTF(SRAM_ATTACH_DEBUG, ("sram%d: devi= 0x%p\n, "
193*11311SSurya.Prakki@Sun.COM 	    " softsp=0x%p\n", instance, (void *)devi, (void *)softsp));
1941708Sstevel 
1951708Sstevel 	/* map in the registers for this device. */
1961708Sstevel 	if (ddi_map_regs(softsp->dip, 0,
1971708Sstevel 	    (caddr_t *)&softsp->sram_base, 0, 0)) {
1981708Sstevel 		cmn_err(CE_WARN, "sram%d: unable to map registers",
1997656SSherry.Moore@Sun.COM 		    instance);
2001708Sstevel 		goto bad;
2011708Sstevel 	}
2021708Sstevel 
2031708Sstevel 	/* nothing to suspend/resume here */
2041708Sstevel 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
2057656SSherry.Moore@Sun.COM 	    "pm-hardware-state", "no-suspend-resume");
2061708Sstevel 
2071708Sstevel 	/* create the kstats for this device. */
2081708Sstevel 	sram_add_kstats(softsp);
2091708Sstevel 
2101708Sstevel 	ddi_report_dev(devi);
2111708Sstevel 
2121708Sstevel 	return (DDI_SUCCESS);
2131708Sstevel 
2141708Sstevel bad:
2151708Sstevel 	ddi_soft_state_free(sramp, instance);
2161708Sstevel 	return (DDI_FAILURE);
2171708Sstevel }
2181708Sstevel 
2191708Sstevel /* ARGSUSED */
2201708Sstevel static int
sram_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)2211708Sstevel sram_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
2221708Sstevel {
2231708Sstevel 	int instance;
2241708Sstevel 	struct sram_soft_state *softsp;
2251708Sstevel 
2261708Sstevel 	/* get the instance of this devi */
2271708Sstevel 	instance = ddi_get_instance(devi);
2281708Sstevel 
2291708Sstevel 	/* get the soft state pointer for this device node */
2301708Sstevel 	softsp = ddi_get_soft_state(sramp, instance);
2311708Sstevel 
2321708Sstevel 	switch (cmd) {
2331708Sstevel 	case DDI_SUSPEND:
2341708Sstevel 		return (DDI_SUCCESS);
2351708Sstevel 
2361708Sstevel 	case DDI_DETACH:
2371708Sstevel 		(void) fhc_bdlist_lock(softsp->board);
2381708Sstevel 		if (fhc_bd_detachable(softsp->board))
2391708Sstevel 			break;
2401708Sstevel 		else
2411708Sstevel 			fhc_bdlist_unlock();
2421708Sstevel 		/* FALLTHROUGH */
2431708Sstevel 
2441708Sstevel 	default:
2451708Sstevel 		return (DDI_FAILURE);
2461708Sstevel 	}
2471708Sstevel 
2481708Sstevel 	fhc_bdlist_unlock();
2491708Sstevel 
2501708Sstevel 	/*
2511708Sstevel 	 * We do not remove the kstat here. There is only one instance for
2521708Sstevel 	 * the whole machine, and it must remain in existence while the
2531708Sstevel 	 * system is running.
2541708Sstevel 	 */
2551708Sstevel 
2561708Sstevel 
2571708Sstevel 	/* unmap the registers */
2581708Sstevel 	ddi_unmap_regs(softsp->dip, 0,
2597656SSherry.Moore@Sun.COM 	    (caddr_t *)&softsp->sram_base, 0, 0);
2601708Sstevel 
2611708Sstevel 	/* free the soft state structure */
2621708Sstevel 	ddi_soft_state_free(sramp, instance);
2631708Sstevel 
2641708Sstevel 	ddi_prop_remove_all(devi);
2651708Sstevel 
2661708Sstevel 	return (DDI_SUCCESS);
2671708Sstevel }
2681708Sstevel 
2691708Sstevel /*
2701708Sstevel  * The Reset-info structure passed up by POST has it's own kstat.
2711708Sstevel  * It only needs to get created once. So the first sram instance
2721708Sstevel  * that gets created will check for the OBP property 'reset-info'
2731708Sstevel  * in the root node of the OBP device tree. If this property exists,
2741708Sstevel  * then the reset-info kstat will get created. Otherwise it will
2751708Sstevel  * not get created. This will inform users whether or not a fatal
2761708Sstevel  * hardware reset has recently occurred.
2771708Sstevel  */
2781708Sstevel static void
sram_add_kstats(struct sram_soft_state * softsp)2791708Sstevel sram_add_kstats(struct sram_soft_state *softsp)
2801708Sstevel {
2811708Sstevel 	int reset_size;		/* size of data collected by POST */
2821708Sstevel 	char *ksptr;		/* memory pointer for byte copy */
2831708Sstevel 	char *srptr;		/* pointer to sram for byte copy */
2841708Sstevel 	int i;
2851708Sstevel 	union  {
2861708Sstevel 		char size[4];	/* copy in word byte-by-byte */
2871708Sstevel 		uint_t len;
2881708Sstevel 	} rst_size;
2891708Sstevel 
2901708Sstevel 	/*
2911708Sstevel 	 * only one reset_info kstat per system, so don't create it if
2921708Sstevel 	 * it exists already.
2931708Sstevel 	 */
2941708Sstevel 	if (reset_info_created) {
2951708Sstevel 		return;
2961708Sstevel 	}
2971708Sstevel 
2981708Sstevel 	/* mark that this code has been run. */
2991708Sstevel 	reset_info_created = 1;
3001708Sstevel 
3011708Sstevel 	/* does the root node have a 'fatal-reset-info' property? */
3021708Sstevel 	if (prom_getprop(prom_rootnode(), "fatal-reset-info",
3031708Sstevel 	    (caddr_t)&softsp->offset) == -1) {
3041708Sstevel 		return;
3051708Sstevel 	}
3061708Sstevel 
3071708Sstevel 	/* XXX - workaround for OBP bug */
3081708Sstevel 	softsp->reset_info = softsp->sram_base + softsp->offset;
3091708Sstevel 
3101708Sstevel 	/*
3111708Sstevel 	 * First read size. In case FW has not word aligned structure,
3121708Sstevel 	 * copy the unsigned int into a 4 byte union, then read it out as
3131708Sstevel 	 * an inteeger.
3141708Sstevel 	 */
3151708Sstevel 	for (i = 0, srptr = softsp->reset_info; i < 4; i++) {
3161708Sstevel 		rst_size.size[i] = *srptr++;
3171708Sstevel 	}
3181708Sstevel 	reset_size = rst_size.len;
3191708Sstevel 
3201708Sstevel 	/*
3211708Sstevel 	 * If the reset size is zero, then POST did not
3221708Sstevel 	 * record any info.
3231708Sstevel 	 */
3241708Sstevel 	if ((uint_t)reset_size == 0) {
3251708Sstevel 		return;
3261708Sstevel 	}
3271708Sstevel 
3281708Sstevel 	/* Check for illegal size values. */
3291708Sstevel 	if ((uint_t)reset_size > MX_RSTINFO_SZ) {
3301708Sstevel 		cmn_err(CE_NOTE, "sram%d: illegal "
3317656SSherry.Moore@Sun.COM 		    "reset_size: 0x%x",
3327656SSherry.Moore@Sun.COM 		    ddi_get_instance(softsp->dip),
3337656SSherry.Moore@Sun.COM 		    reset_size);
3341708Sstevel 		return;
3351708Sstevel 	}
3361708Sstevel 
3371708Sstevel 	/* create the reset-info kstat */
3381708Sstevel 	resetinfo_ksp = kstat_create("unix", 0,
3397656SSherry.Moore@Sun.COM 	    RESETINFO_KSTAT_NAME, "misc", KSTAT_TYPE_RAW,
3407656SSherry.Moore@Sun.COM 	    reset_size, KSTAT_FLAG_PERSISTENT);
3411708Sstevel 
3421708Sstevel 	if (resetinfo_ksp == NULL) {
3431708Sstevel 		cmn_err(CE_WARN, "sram%d: kstat_create failed",
3447656SSherry.Moore@Sun.COM 		    ddi_get_instance(softsp->dip));
3451708Sstevel 		return;
3461708Sstevel 	}
3471708Sstevel 
3481708Sstevel 	/*
3491708Sstevel 	 * now copy the data into kstat. Don't use block
3501708Sstevel 	 * copy, the local space sram does not support this.
3511708Sstevel 	 */
3521708Sstevel 	srptr = softsp->reset_info;
3531708Sstevel 
3541708Sstevel 	ksptr = (char *)resetinfo_ksp->ks_data;
3551708Sstevel 
3561708Sstevel 	for (i = 0; i < reset_size; i++) {
3571708Sstevel 		*ksptr++ = *srptr++;
3581708Sstevel 	}
3591708Sstevel 
3601708Sstevel 	kstat_install(resetinfo_ksp);
3611708Sstevel }
362