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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/conf.h> 28 #include <sys/kmem.h> 29 #include <sys/open.h> 30 #include <sys/ddi.h> 31 #include <sys/sunddi.h> 32 33 #include <sys/todm5819.h> 34 #include <sys/modctl.h> 35 #include <sys/stat.h> 36 #include <sys/clock.h> 37 #include <sys/reboot.h> 38 #include <sys/machsystm.h> 39 #include <sys/poll.h> 40 #include <sys/pbio.h> 41 #include <sys/lom_priv.h> 42 43 #define WDOG_ON 1 44 #define WDOG_OFF 0 45 46 static timestruc_t todbl_get(void); 47 static void todbl_set(timestruc_t); 48 static uint_t todbl_set_watchdog_timer(uint_t); 49 static uint_t todbl_clear_watchdog_timer(void); 50 static void todbl_set_power_alarm(timestruc_t); 51 static void todbl_clear_power_alarm(void); 52 static uint64_t todbl_get_cpufrequency(void); 53 54 static todinfo_t rtc_to_tod(struct rtc_t *); 55 static uint_t read_rtc(struct rtc_t *); 56 static void write_rtc_time(struct rtc_t *); 57 static uint_t configure_wdog(uint8_t new_state); 58 59 extern uint64_t find_cpufrequency(volatile uint8_t *); 60 61 /* 62 * External variables 63 */ 64 extern int watchdog_enable; 65 extern int watchdog_available; 66 extern int watchdog_activated; 67 extern uint_t watchdog_timeout_seconds; 68 extern int boothowto; 69 extern void (*bsc_drv_func_ptr)(struct bscv_idi_info *); 70 71 /* 72 * Global variables 73 */ 74 int m5819_debug_flags; 75 uint8_t wdog_reset_on_timeout = 1; 76 static clock_t last_pat_lbt; 77 78 79 static struct modlmisc modlmisc = { 80 &mod_miscops, "todblade module", 81 }; 82 83 static struct modlinkage modlinkage = { 84 MODREV_1, &modlmisc, NULL 85 }; 86 87 88 int 89 _init(void) 90 { 91 if (strcmp(tod_module_name, "todblade") == 0) { 92 RTC_PUT8(RTC_B, (RTC_DM | RTC_HM)); 93 94 tod_ops.tod_get = todbl_get; 95 tod_ops.tod_set = todbl_set; 96 tod_ops.tod_set_watchdog_timer = 97 todbl_set_watchdog_timer; 98 tod_ops.tod_clear_watchdog_timer = 99 todbl_clear_watchdog_timer; 100 tod_ops.tod_set_power_alarm = todbl_set_power_alarm; 101 tod_ops.tod_clear_power_alarm = todbl_clear_power_alarm; 102 tod_ops.tod_get_cpufrequency = todbl_get_cpufrequency; 103 104 if (watchdog_enable && (boothowto & RB_DEBUG)) { 105 watchdog_available = 0; 106 cmn_err(CE_WARN, "todblade: kernel debugger " 107 "detected: hardware watchdog disabled"); 108 } 109 } 110 return (mod_install(&modlinkage)); 111 } 112 113 int 114 _fini(void) 115 { 116 if (strcmp(tod_module_name, "todblade") == 0) { 117 return (EBUSY); 118 } else { 119 return (mod_remove(&modlinkage)); 120 } 121 } 122 123 /* 124 * The loadable-module _info(9E) entry point 125 */ 126 int 127 _info(struct modinfo *modinfop) 128 { 129 return (mod_info(&modlinkage, modinfop)); 130 } 131 132 133 /* 134 * Read the current time from the clock chip and convert to UNIX form. 135 * Assumes that the year in the clock chip is valid. 136 * Must be called with tod_lock held. 137 */ 138 static timestruc_t 139 todbl_get(void) 140 { 141 int i; 142 timestruc_t ts; 143 struct rtc_t rtc; 144 struct bscv_idi_info bscv_info; 145 146 ASSERT(MUTEX_HELD(&tod_lock)); 147 148 /* 149 * We must check that the value of watchdog enable hasnt changed 150 * as its a user knob for turning it on and off 151 */ 152 if (watchdog_available) { 153 if (watchdog_activated && !watchdog_enable) { 154 (void) configure_wdog(WDOG_OFF); 155 } else if (!watchdog_activated && watchdog_enable) { 156 (void) configure_wdog(WDOG_ON); 157 } else if (watchdog_activated && 158 (ddi_get_lbolt() - last_pat_lbt) >= 159 SEC_TO_TICK(1)) { 160 /* 161 * PAT THE WATCHDOG!! 162 * We dont want to accelerate the pat frequency 163 * when userland calls to the TOD_GET_DATE ioctl 164 * pass through here. 165 */ 166 bscv_info.type = BSCV_IDI_WDOG_PAT; 167 bscv_info.data = NULL; 168 bscv_info.size = 0; 169 if (bsc_drv_func_ptr != NULL) { 170 (*bsc_drv_func_ptr)(&bscv_info); 171 last_pat_lbt = ddi_get_lbolt(); 172 } 173 } 174 } 175 176 /* 177 * Read from the tod, and if it isnt accessible wait 178 * before retrying. 179 */ 180 for (i = 0; i < TODM5819_UIP_RETRY_THRESH; i++) { 181 if (read_rtc(&rtc)) 182 break; 183 drv_usecwait(TODM5819_UIP_WAIT_USEC); 184 } 185 if (i == TODM5819_UIP_RETRY_THRESH) { 186 /* 187 * We couldnt read from the tod 188 */ 189 tod_fault_reset(); 190 return (hrestime); 191 } 192 193 DPRINTF("todbl_get: century=%d year=%d dom=%d hrs=%d\n", 194 rtc.rtc_century, rtc.rtc_year, rtc.rtc_dom, rtc.rtc_hrs); 195 196 ts.tv_sec = tod_to_utc(rtc_to_tod(&rtc)); 197 ts.tv_nsec = 0; 198 return (ts); 199 } 200 201 static todinfo_t 202 rtc_to_tod(struct rtc_t *rtc) 203 { 204 todinfo_t tod; 205 206 /* 207 * tod_year is base 1900 so this code needs to adjust the true 208 * year retrieved from the rtc's century and year fields. 209 */ 210 tod.tod_year = rtc->rtc_year + (rtc->rtc_century * 100) - 1900; 211 tod.tod_month = rtc->rtc_mon; 212 tod.tod_day = rtc->rtc_dom; 213 tod.tod_dow = rtc->rtc_dow; 214 tod.tod_hour = rtc->rtc_hrs; 215 tod.tod_min = rtc->rtc_min; 216 tod.tod_sec = rtc->rtc_sec; 217 218 return (tod); 219 } 220 221 222 static uint_t 223 read_rtc(struct rtc_t *rtc) 224 { 225 int s; 226 uint_t rtc_readable = 0; 227 228 s = splhi(); 229 /* 230 * If UIP bit is not set we have at least 274us 231 * to read the values. 232 */ 233 if (!(RTC_GET8(RTC_A) & RTC_UIP)) { 234 rtc_readable = 1; 235 236 rtc->rtc_sec = RTC_GET8(RTC_SEC); 237 rtc->rtc_asec = RTC_GET8(RTC_ASEC); 238 rtc->rtc_min = RTC_GET8(RTC_MIN); 239 rtc->rtc_amin = RTC_GET8(RTC_AMIN); 240 241 rtc->rtc_hrs = RTC_GET8(RTC_HRS); 242 rtc->rtc_ahrs = RTC_GET8(RTC_AHRS); 243 rtc->rtc_dow = RTC_GET8(RTC_DOW); 244 rtc->rtc_dom = RTC_GET8(RTC_DOM); 245 rtc->rtc_adom = RTC_GET8(RTC_D) & 0x3f; 246 247 rtc->rtc_mon = RTC_GET8(RTC_MON); 248 rtc->rtc_year = RTC_GET8(RTC_YEAR); 249 rtc->rtc_century = RTC_GET8(RTC_CENTURY); 250 rtc->rtc_amon = 0; 251 252 /* Clear wakeup data */ 253 rtc->apc_wdwr = 0; 254 rtc->apc_wdmr = 0; 255 rtc->apc_wmr = 0; 256 rtc->apc_wyr = 0; 257 rtc->apc_wcr = 0; 258 } 259 260 splx(s); 261 return (rtc_readable); 262 } 263 264 /* 265 * Write the specified time into the clock chip. 266 * Must be called with tod_lock held. 267 */ 268 static void 269 todbl_set(timestruc_t ts) 270 { 271 struct rtc_t rtc; 272 todinfo_t tod = utc_to_tod(ts.tv_sec); 273 struct bscv_idi_info bscv_info; 274 int year; 275 276 ASSERT(MUTEX_HELD(&tod_lock)); 277 278 /* tod_year is base 1900 so this code needs to adjust */ 279 year = 1900 + tod.tod_year; 280 rtc.rtc_year = year % 100; 281 rtc.rtc_century = year / 100; 282 rtc.rtc_mon = (uint8_t)tod.tod_month; 283 rtc.rtc_dom = (uint8_t)tod.tod_day; 284 rtc.rtc_dow = (uint8_t)tod.tod_dow; 285 rtc.rtc_hrs = (uint8_t)tod.tod_hour; 286 rtc.rtc_min = (uint8_t)tod.tod_min; 287 rtc.rtc_sec = (uint8_t)tod.tod_sec; 288 DPRINTF("todbl_set: century=%d year=%d dom=%d hrs=%d\n", 289 rtc.rtc_century, rtc.rtc_year, rtc.rtc_dom, rtc.rtc_hrs); 290 291 write_rtc_time(&rtc); 292 293 /* 294 * Because of a generic solaris problem where calls to stime() 295 * starve calls to tod_get(), we need to check to see when the 296 * watchdog was last patted and pat it if necessary. 297 */ 298 if (watchdog_activated && 299 (ddi_get_lbolt() - last_pat_lbt) >= SEC_TO_TICK(1)) { 300 /* 301 * Pat the watchdog! 302 */ 303 bscv_info.type = BSCV_IDI_WDOG_PAT; 304 bscv_info.data = NULL; 305 bscv_info.size = 0; 306 if (bsc_drv_func_ptr != NULL) { 307 (*bsc_drv_func_ptr)(&bscv_info); 308 last_pat_lbt = ddi_get_lbolt(); 309 } 310 } 311 } 312 313 static void 314 write_rtc_time(struct rtc_t *rtc) 315 { 316 uint8_t regb; 317 318 /* 319 * Freeze 320 */ 321 regb = RTC_GET8(RTC_B); 322 RTC_PUT8(RTC_B, (regb | RTC_SET)); 323 324 RTC_PUT8(RTC_SEC, (rtc->rtc_sec)); 325 RTC_PUT8(RTC_ASEC, (rtc->rtc_asec)); 326 RTC_PUT8(RTC_MIN, (rtc->rtc_min)); 327 RTC_PUT8(RTC_AMIN, (rtc->rtc_amin)); 328 329 RTC_PUT8(RTC_HRS, (rtc->rtc_hrs)); 330 RTC_PUT8(RTC_AHRS, (rtc->rtc_ahrs)); 331 RTC_PUT8(RTC_DOW, (rtc->rtc_dow)); 332 RTC_PUT8(RTC_DOM, (rtc->rtc_dom)); 333 334 RTC_PUT8(RTC_MON, (rtc->rtc_mon)); 335 RTC_PUT8(RTC_YEAR, (rtc->rtc_year)); 336 RTC_PUT8(RTC_CENTURY, (rtc->rtc_century)); 337 338 /* 339 * Unfreeze 340 */ 341 RTC_PUT8(RTC_B, regb); 342 } 343 344 345 346 /* 347 * The TOD alarm functionality is not supported on our platform 348 * as the interrupt is not wired, so do nothing. 349 */ 350 /*ARGSUSED*/ 351 static void 352 todbl_set_power_alarm(timestruc_t ts) 353 { 354 ASSERT(MUTEX_HELD(&tod_lock)); 355 } 356 357 /* 358 * clear alarm interrupt 359 */ 360 static void 361 todbl_clear_power_alarm(void) 362 { 363 ASSERT(MUTEX_HELD(&tod_lock)); 364 } 365 366 /* 367 * Determine the cpu frequency by watching the TOD chip rollover twice. 368 * Cpu clock rate is determined by computing the ticks added (in tick register) 369 * during one second interval on TOD. 370 */ 371 uint64_t 372 todbl_get_cpufrequency(void) 373 { 374 ASSERT(MUTEX_HELD(&tod_lock)); 375 M5819_ADDR_REG = RTC_SEC; 376 return (find_cpufrequency(v_rtc_data_reg)); 377 } 378 379 380 static uint_t 381 todbl_set_watchdog_timer(uint_t timeoutval) 382 { 383 /* 384 * We get started during kernel intilaisation only 385 * if watchdog_enable is set. 386 */ 387 ASSERT(MUTEX_HELD(&tod_lock)); 388 389 if (watchdog_available && (!watchdog_activated || 390 (watchdog_activated && (timeoutval != watchdog_timeout_seconds)))) { 391 watchdog_timeout_seconds = timeoutval; 392 if (configure_wdog(WDOG_ON)) 393 return (watchdog_timeout_seconds); 394 } 395 return (0); 396 } 397 398 static uint_t 399 todbl_clear_watchdog_timer(void) 400 { 401 /* 402 * The core kernel will call us here to disable the wdog when: 403 * 1. we're panicing 404 * 2. we're entering debug 405 * 3. we're rebooting 406 */ 407 ASSERT(MUTEX_HELD(&tod_lock)); 408 409 if (watchdog_available && watchdog_activated) { 410 watchdog_enable = 0; 411 if (!configure_wdog(WDOG_OFF)) 412 return (0); 413 } 414 return (watchdog_timeout_seconds); 415 } 416 417 static uint_t 418 configure_wdog(uint8_t new_state) 419 { 420 bscv_wdog_t wdog_cmd; 421 struct bscv_idi_info bscv_info; 422 423 if (new_state == WDOG_ON || new_state == WDOG_OFF) { 424 425 wdog_cmd.enable_wdog = new_state; 426 wdog_cmd.wdog_timeout_s = watchdog_timeout_seconds; 427 wdog_cmd.reset_system_on_timeout = wdog_reset_on_timeout; 428 bscv_info.type = BSCV_IDI_WDOG_CFG; 429 bscv_info.data = &wdog_cmd; 430 bscv_info.size = sizeof (wdog_cmd); 431 432 if (bsc_drv_func_ptr != NULL) { 433 watchdog_activated = new_state; 434 (*bsc_drv_func_ptr)(&bscv_info); 435 return (1); 436 } 437 } 438 return (0); 439 440 } 441