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