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 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, (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 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