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