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