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 */
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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)151 _info(struct modinfo *modinfop)
152 {
153 return (mod_info(&modlinkage, modinfop));
154 }
155
156 static int
sram_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)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, (void *)devi, (void *)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
sram_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)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
sram_add_kstats(struct sram_soft_state * softsp)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