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