xref: /onnv-gate/usr/src/uts/sun4u/sunfire/io/sram.c (revision 1708:ea74d8598a3a)
1*1708Sstevel /*
2*1708Sstevel  * CDDL HEADER START
3*1708Sstevel  *
4*1708Sstevel  * The contents of this file are subject to the terms of the
5*1708Sstevel  * Common Development and Distribution License (the "License").
6*1708Sstevel  * You may not use this file except in compliance with the License.
7*1708Sstevel  *
8*1708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1708Sstevel  * or http://www.opensolaris.org/os/licensing.
10*1708Sstevel  * See the License for the specific language governing permissions
11*1708Sstevel  * and limitations under the License.
12*1708Sstevel  *
13*1708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
14*1708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
16*1708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
17*1708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1708Sstevel  *
19*1708Sstevel  * CDDL HEADER END
20*1708Sstevel  */
21*1708Sstevel 
22*1708Sstevel /*
23*1708Sstevel  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*1708Sstevel  * Use is subject to license terms.
25*1708Sstevel  */
26*1708Sstevel 
27*1708Sstevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*1708Sstevel 
29*1708Sstevel #include <sys/types.h>
30*1708Sstevel #include <sys/conf.h>
31*1708Sstevel #include <sys/ddi.h>
32*1708Sstevel #include <sys/sunddi.h>
33*1708Sstevel #include <sys/ddi_impldefs.h>
34*1708Sstevel #include <sys/obpdefs.h>
35*1708Sstevel #include <sys/cmn_err.h>
36*1708Sstevel #include <sys/errno.h>
37*1708Sstevel #include <sys/kmem.h>
38*1708Sstevel #include <sys/debug.h>
39*1708Sstevel #include <sys/sysmacros.h>
40*1708Sstevel #include <sys/autoconf.h>
41*1708Sstevel #include <sys/modctl.h>
42*1708Sstevel 
43*1708Sstevel #include <sys/fhc.h>
44*1708Sstevel #include <sys/sram.h>
45*1708Sstevel #include <sys/promif.h>
46*1708Sstevel 
47*1708Sstevel /* Useful debugging Stuff */
48*1708Sstevel #include <sys/nexusdebug.h>
49*1708Sstevel 
50*1708Sstevel /*
51*1708Sstevel  * Function protoypes
52*1708Sstevel  */
53*1708Sstevel 
54*1708Sstevel static int sram_attach(dev_info_t *, ddi_attach_cmd_t);
55*1708Sstevel 
56*1708Sstevel static int sram_detach(dev_info_t *, ddi_detach_cmd_t);
57*1708Sstevel 
58*1708Sstevel static void sram_add_kstats(struct sram_soft_state *);
59*1708Sstevel 
60*1708Sstevel /*
61*1708Sstevel  * Configuration data structures
62*1708Sstevel  */
63*1708Sstevel static struct cb_ops sram_cb_ops = {
64*1708Sstevel 	nulldev,			/* open */
65*1708Sstevel 	nulldev,			/* close */
66*1708Sstevel 	nulldev,			/* strategy */
67*1708Sstevel 	nulldev,			/* print */
68*1708Sstevel 	nodev,				/* dump */
69*1708Sstevel 	nulldev,			/* read */
70*1708Sstevel 	nulldev,			/* write */
71*1708Sstevel 	nulldev,			/* ioctl */
72*1708Sstevel 	nodev,				/* devmap */
73*1708Sstevel 	nodev,				/* mmap */
74*1708Sstevel 	nodev,				/* segmap */
75*1708Sstevel 	nochpoll,			/* poll */
76*1708Sstevel 	ddi_prop_op,			/* cb_prop_op */
77*1708Sstevel 	0,				/* streamtab */
78*1708Sstevel 	D_MP | D_NEW | D_HOTPLUG,	/* Driver compatibility flag */
79*1708Sstevel 	CB_REV,				/* rev */
80*1708Sstevel 	nodev,				/* cb_aread */
81*1708Sstevel 	nodev				/* cb_awrite */
82*1708Sstevel };
83*1708Sstevel 
84*1708Sstevel static struct dev_ops sram_ops = {
85*1708Sstevel 	DEVO_REV,			/* rev */
86*1708Sstevel 	0,				/* refcnt  */
87*1708Sstevel 	ddi_no_info,			/* getinfo */
88*1708Sstevel 	nulldev,			/* identify */
89*1708Sstevel 	nulldev,			/* probe */
90*1708Sstevel 	sram_attach,			/* attach */
91*1708Sstevel 	sram_detach,			/* detach */
92*1708Sstevel 	nulldev,			/* reset */
93*1708Sstevel 	&sram_cb_ops,			/* cb_ops */
94*1708Sstevel 	(struct bus_ops *)0,		/* bus_ops */
95*1708Sstevel 	nulldev				/* power */
96*1708Sstevel };
97*1708Sstevel 
98*1708Sstevel 
99*1708Sstevel /*
100*1708Sstevel  * Driver globals
101*1708Sstevel  */
102*1708Sstevel void *sramp;			/* sram soft state hook */
103*1708Sstevel static struct kstat *resetinfo_ksp = NULL;
104*1708Sstevel static int reset_info_created = 0;
105*1708Sstevel 
106*1708Sstevel extern struct mod_ops mod_driverops;
107*1708Sstevel 
108*1708Sstevel static struct modldrv modldrv = {
109*1708Sstevel 	&mod_driverops,		/* Type of module.  This one is a driver */
110*1708Sstevel 	"Sram Leaf v%I%",	/* name of module */
111*1708Sstevel 	&sram_ops,		/* driver ops */
112*1708Sstevel };
113*1708Sstevel 
114*1708Sstevel static struct modlinkage modlinkage = {
115*1708Sstevel 	MODREV_1,
116*1708Sstevel 	(void *)&modldrv,
117*1708Sstevel 	NULL
118*1708Sstevel };
119*1708Sstevel 
120*1708Sstevel #ifndef	lint
121*1708Sstevel char _depends_on[] = "drv/fhc";
122*1708Sstevel #endif	/* lint */
123*1708Sstevel 
124*1708Sstevel /*
125*1708Sstevel  * These are the module initialization routines.
126*1708Sstevel  */
127*1708Sstevel 
128*1708Sstevel int
129*1708Sstevel _init(void)
130*1708Sstevel {
131*1708Sstevel 	int error;
132*1708Sstevel 
133*1708Sstevel 	if ((error = ddi_soft_state_init(&sramp,
134*1708Sstevel 	    sizeof (struct sram_soft_state), 1)) == 0 &&
135*1708Sstevel 	    (error = mod_install(&modlinkage)) != 0)
136*1708Sstevel 		ddi_soft_state_fini(&sramp);
137*1708Sstevel 	return (error);
138*1708Sstevel }
139*1708Sstevel 
140*1708Sstevel int
141*1708Sstevel _fini(void)
142*1708Sstevel {
143*1708Sstevel 	int error;
144*1708Sstevel 
145*1708Sstevel 	if ((error = mod_remove(&modlinkage)) == 0)
146*1708Sstevel 		ddi_soft_state_fini(&sramp);
147*1708Sstevel 	return (error);
148*1708Sstevel }
149*1708Sstevel 
150*1708Sstevel int
151*1708Sstevel _info(struct modinfo *modinfop)
152*1708Sstevel {
153*1708Sstevel 	return (mod_info(&modlinkage, modinfop));
154*1708Sstevel }
155*1708Sstevel 
156*1708Sstevel static int
157*1708Sstevel sram_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
158*1708Sstevel {
159*1708Sstevel 	int instance;
160*1708Sstevel 	struct sram_soft_state *softsp;
161*1708Sstevel 
162*1708Sstevel 	switch (cmd) {
163*1708Sstevel 	case DDI_ATTACH:
164*1708Sstevel 		break;
165*1708Sstevel 
166*1708Sstevel 	case DDI_RESUME:
167*1708Sstevel 		return (DDI_SUCCESS);
168*1708Sstevel 
169*1708Sstevel 	default:
170*1708Sstevel 		return (DDI_FAILURE);
171*1708Sstevel 	}
172*1708Sstevel 
173*1708Sstevel 	instance = ddi_get_instance(devi);
174*1708Sstevel 
175*1708Sstevel 	if (ddi_soft_state_zalloc(sramp, instance) != DDI_SUCCESS)
176*1708Sstevel 		return (DDI_FAILURE);
177*1708Sstevel 
178*1708Sstevel 	softsp = ddi_get_soft_state(sramp, instance);
179*1708Sstevel 
180*1708Sstevel 	/* Set the dip in the soft state */
181*1708Sstevel 	softsp->dip = devi;
182*1708Sstevel 
183*1708Sstevel 	/* get the board number from this devices parent. */
184*1708Sstevel 	softsp->pdip = ddi_get_parent(softsp->dip);
185*1708Sstevel 	if ((softsp->board = (int)ddi_getprop(DDI_DEV_T_ANY, softsp->pdip,
186*1708Sstevel 	    DDI_PROP_DONTPASS, OBP_BOARDNUM, -1)) == -1) {
187*1708Sstevel 		cmn_err(CE_WARN, "sram%d: unable to retrieve %s property",
188*1708Sstevel 			instance, OBP_BOARDNUM);
189*1708Sstevel 		goto bad;
190*1708Sstevel 	}
191*1708Sstevel 
192*1708Sstevel 	DPRINTF(SRAM_ATTACH_DEBUG, ("sram%d: devi= 0x%p\n, "
193*1708Sstevel 		" softsp=0x%p\n", instance, devi, softsp));
194*1708Sstevel 
195*1708Sstevel 	/* map in the registers for this device. */
196*1708Sstevel 	if (ddi_map_regs(softsp->dip, 0,
197*1708Sstevel 	    (caddr_t *)&softsp->sram_base, 0, 0)) {
198*1708Sstevel 		cmn_err(CE_WARN, "sram%d: unable to map registers",
199*1708Sstevel 			instance);
200*1708Sstevel 		goto bad;
201*1708Sstevel 	}
202*1708Sstevel 
203*1708Sstevel 	/* nothing to suspend/resume here */
204*1708Sstevel 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devi,
205*1708Sstevel 		"pm-hardware-state", "no-suspend-resume");
206*1708Sstevel 
207*1708Sstevel 	/* create the kstats for this device. */
208*1708Sstevel 	sram_add_kstats(softsp);
209*1708Sstevel 
210*1708Sstevel 	ddi_report_dev(devi);
211*1708Sstevel 
212*1708Sstevel 	return (DDI_SUCCESS);
213*1708Sstevel 
214*1708Sstevel bad:
215*1708Sstevel 	ddi_soft_state_free(sramp, instance);
216*1708Sstevel 	return (DDI_FAILURE);
217*1708Sstevel }
218*1708Sstevel 
219*1708Sstevel /* ARGSUSED */
220*1708Sstevel static int
221*1708Sstevel sram_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
222*1708Sstevel {
223*1708Sstevel 	int instance;
224*1708Sstevel 	struct sram_soft_state *softsp;
225*1708Sstevel 
226*1708Sstevel 	/* get the instance of this devi */
227*1708Sstevel 	instance = ddi_get_instance(devi);
228*1708Sstevel 
229*1708Sstevel 	/* get the soft state pointer for this device node */
230*1708Sstevel 	softsp = ddi_get_soft_state(sramp, instance);
231*1708Sstevel 
232*1708Sstevel 	switch (cmd) {
233*1708Sstevel 	case DDI_SUSPEND:
234*1708Sstevel 		return (DDI_SUCCESS);
235*1708Sstevel 
236*1708Sstevel 	case DDI_DETACH:
237*1708Sstevel 		(void) fhc_bdlist_lock(softsp->board);
238*1708Sstevel 		if (fhc_bd_detachable(softsp->board))
239*1708Sstevel 			break;
240*1708Sstevel 		else
241*1708Sstevel 			fhc_bdlist_unlock();
242*1708Sstevel 		/* FALLTHROUGH */
243*1708Sstevel 
244*1708Sstevel 	default:
245*1708Sstevel 		return (DDI_FAILURE);
246*1708Sstevel 	}
247*1708Sstevel 
248*1708Sstevel 	fhc_bdlist_unlock();
249*1708Sstevel 
250*1708Sstevel 	/*
251*1708Sstevel 	 * We do not remove the kstat here. There is only one instance for
252*1708Sstevel 	 * the whole machine, and it must remain in existence while the
253*1708Sstevel 	 * system is running.
254*1708Sstevel 	 */
255*1708Sstevel 
256*1708Sstevel 
257*1708Sstevel 	/* unmap the registers */
258*1708Sstevel 	ddi_unmap_regs(softsp->dip, 0,
259*1708Sstevel 		(caddr_t *)&softsp->sram_base, 0, 0);
260*1708Sstevel 
261*1708Sstevel 	/* free the soft state structure */
262*1708Sstevel 	ddi_soft_state_free(sramp, instance);
263*1708Sstevel 
264*1708Sstevel 	ddi_prop_remove_all(devi);
265*1708Sstevel 
266*1708Sstevel 	return (DDI_SUCCESS);
267*1708Sstevel }
268*1708Sstevel 
269*1708Sstevel /*
270*1708Sstevel  * The Reset-info structure passed up by POST has it's own kstat.
271*1708Sstevel  * It only needs to get created once. So the first sram instance
272*1708Sstevel  * that gets created will check for the OBP property 'reset-info'
273*1708Sstevel  * in the root node of the OBP device tree. If this property exists,
274*1708Sstevel  * then the reset-info kstat will get created. Otherwise it will
275*1708Sstevel  * not get created. This will inform users whether or not a fatal
276*1708Sstevel  * hardware reset has recently occurred.
277*1708Sstevel  */
278*1708Sstevel static void
279*1708Sstevel sram_add_kstats(struct sram_soft_state *softsp)
280*1708Sstevel {
281*1708Sstevel 	int reset_size;		/* size of data collected by POST */
282*1708Sstevel 	char *ksptr;		/* memory pointer for byte copy */
283*1708Sstevel 	char *srptr;		/* pointer to sram for byte copy */
284*1708Sstevel 	int i;
285*1708Sstevel 	union  {
286*1708Sstevel 		char size[4];	/* copy in word byte-by-byte */
287*1708Sstevel 		uint_t len;
288*1708Sstevel 	} rst_size;
289*1708Sstevel 
290*1708Sstevel 	/*
291*1708Sstevel 	 * only one reset_info kstat per system, so don't create it if
292*1708Sstevel 	 * it exists already.
293*1708Sstevel 	 */
294*1708Sstevel 	if (reset_info_created) {
295*1708Sstevel 		return;
296*1708Sstevel 	}
297*1708Sstevel 
298*1708Sstevel 	/* mark that this code has been run. */
299*1708Sstevel 	reset_info_created = 1;
300*1708Sstevel 
301*1708Sstevel 	/* does the root node have a 'fatal-reset-info' property? */
302*1708Sstevel 	if (prom_getprop(prom_rootnode(), "fatal-reset-info",
303*1708Sstevel 	    (caddr_t)&softsp->offset) == -1) {
304*1708Sstevel 		return;
305*1708Sstevel 	}
306*1708Sstevel 
307*1708Sstevel 	/* XXX - workaround for OBP bug */
308*1708Sstevel 	softsp->reset_info = softsp->sram_base + softsp->offset;
309*1708Sstevel 
310*1708Sstevel 	/*
311*1708Sstevel 	 * First read size. In case FW has not word aligned structure,
312*1708Sstevel 	 * copy the unsigned int into a 4 byte union, then read it out as
313*1708Sstevel 	 * an inteeger.
314*1708Sstevel 	 */
315*1708Sstevel 	for (i = 0, srptr = softsp->reset_info; i < 4; i++) {
316*1708Sstevel 		rst_size.size[i] = *srptr++;
317*1708Sstevel 	}
318*1708Sstevel 	reset_size = rst_size.len;
319*1708Sstevel 
320*1708Sstevel 	/*
321*1708Sstevel 	 * If the reset size is zero, then POST did not
322*1708Sstevel 	 * record any info.
323*1708Sstevel 	 */
324*1708Sstevel 	if ((uint_t)reset_size == 0) {
325*1708Sstevel 		return;
326*1708Sstevel 	}
327*1708Sstevel 
328*1708Sstevel 	/* Check for illegal size values. */
329*1708Sstevel 	if ((uint_t)reset_size > MX_RSTINFO_SZ) {
330*1708Sstevel 		cmn_err(CE_NOTE, "sram%d: illegal "
331*1708Sstevel 			"reset_size: 0x%x",
332*1708Sstevel 			ddi_get_instance(softsp->dip),
333*1708Sstevel 			reset_size);
334*1708Sstevel 		return;
335*1708Sstevel 	}
336*1708Sstevel 
337*1708Sstevel 	/* create the reset-info kstat */
338*1708Sstevel 	resetinfo_ksp = kstat_create("unix", 0,
339*1708Sstevel 		RESETINFO_KSTAT_NAME, "misc", KSTAT_TYPE_RAW,
340*1708Sstevel 		reset_size, KSTAT_FLAG_PERSISTENT);
341*1708Sstevel 
342*1708Sstevel 	if (resetinfo_ksp == NULL) {
343*1708Sstevel 		cmn_err(CE_WARN, "sram%d: kstat_create failed",
344*1708Sstevel 			ddi_get_instance(softsp->dip));
345*1708Sstevel 		return;
346*1708Sstevel 	}
347*1708Sstevel 
348*1708Sstevel 	/*
349*1708Sstevel 	 * now copy the data into kstat. Don't use block
350*1708Sstevel 	 * copy, the local space sram does not support this.
351*1708Sstevel 	 */
352*1708Sstevel 	srptr = softsp->reset_info;
353*1708Sstevel 
354*1708Sstevel 	ksptr = (char *)resetinfo_ksp->ks_data;
355*1708Sstevel 
356*1708Sstevel 	for (i = 0; i < reset_size; i++) {
357*1708Sstevel 		*ksptr++ = *srptr++;
358*1708Sstevel 	}
359*1708Sstevel 
360*1708Sstevel 	kstat_install(resetinfo_ksp);
361*1708Sstevel }
362