ip27-timer.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:7k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Copytight (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
  3.  * Copytight (C) 1999, 2000 Silicon Graphics, Inc.
  4.  */
  5. #include <linux/config.h>
  6. #include <linux/init.h>
  7. #include <linux/kernel.h>
  8. #include <linux/sched.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/kernel_stat.h>
  11. #include <linux/param.h>
  12. #include <linux/timex.h>
  13. #include <linux/mm.h>
  14. #include <asm/pgtable.h>
  15. #include <asm/sgialib.h>
  16. #include <asm/sn/ioc3.h>
  17. #include <asm/m48t35.h>
  18. #include <asm/sn/klconfig.h>
  19. #include <asm/sn/arch.h>
  20. #include <asm/sn/addrs.h>
  21. #include <asm/sn/sn_private.h>
  22. #include <asm/sn/sn0/ip27.h>
  23. #include <asm/sn/sn0/hub.h>
  24. /*
  25.  * This is a hack; we really need to figure these values out dynamically
  26.  * 
  27.  * Since 800 ns works very well with various HUB frequencies, such as
  28.  * 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time.
  29.  *
  30.  * Ralf: which clock rate is used to feed the counter?
  31.  */
  32. #define NSEC_PER_CYCLE 800
  33. #define NSEC_PER_SEC 1000000000
  34. #define CYCLES_PER_SEC (NSEC_PER_SEC/NSEC_PER_CYCLE)
  35. #define CYCLES_PER_JIFFY (CYCLES_PER_SEC/HZ)
  36. static unsigned long ct_cur[NR_CPUS]; /* What counter should be at next timer irq */
  37. static long last_rtc_update; /* Last time the rtc clock got updated */
  38. extern rwlock_t xtime_lock;
  39. extern volatile unsigned long wall_jiffies;
  40. static int set_rtc_mmss(unsigned long nowtime)
  41. {
  42. int retval = 0;
  43. int real_seconds, real_minutes, cmos_minutes;
  44. struct m48t35_rtc *rtc;
  45. nasid_t nid;
  46. nid = get_nasid();
  47. rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base + 
  48. IOC3_BYTEBUS_DEV0);
  49. rtc->control |= M48T35_RTC_READ;
  50. cmos_minutes = rtc->min;
  51. BCD_TO_BIN(cmos_minutes);
  52. rtc->control &= ~M48T35_RTC_READ;
  53. /*
  54.  * Since we're only adjusting minutes and seconds, don't interfere with
  55.  * hour overflow. This avoids messing with unknown time zones but
  56.  * requires your RTC not to be off by more than 15 minutes
  57.  */
  58. real_seconds = nowtime % 60;
  59. real_minutes = nowtime / 60;
  60. if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
  61. real_minutes += 30; /* correct for half hour time zone */
  62. real_minutes %= 60;
  63. if (abs(real_minutes - cmos_minutes) < 30) {
  64. BIN_TO_BCD(real_seconds);
  65. BIN_TO_BCD(real_minutes);
  66. rtc->control |= M48T35_RTC_SET;
  67. rtc->sec = real_seconds;
  68. rtc->min = real_minutes;
  69. rtc->control &= ~M48T35_RTC_SET;
  70. } else {
  71. printk(KERN_WARNING
  72.        "set_rtc_mmss: can't update from %d to %dn",
  73.        cmos_minutes, real_minutes);
  74. retval = -1;
  75. }
  76. return retval;
  77. }
  78. void rt_timer_interrupt(struct pt_regs *regs)
  79. {
  80. int cpu = smp_processor_id();
  81. int cpuA = ((cputoslice(cpu)) == 0);
  82. int irq = 7; /* XXX Assign number */
  83. write_lock(&xtime_lock);
  84. again:
  85. LOCAL_HUB_S(cpuA ? PI_RT_PEND_A : PI_RT_PEND_B, 0); /* Ack  */
  86. ct_cur[cpu] += CYCLES_PER_JIFFY;
  87. LOCAL_HUB_S(cpuA ? PI_RT_COMPARE_A : PI_RT_COMPARE_B, ct_cur[cpu]);
  88. if (LOCAL_HUB_L(PI_RT_COUNT) >= ct_cur[cpu])
  89. goto again;
  90. kstat.irqs[cpu][irq]++; /* kstat only for bootcpu? */
  91. if (cpu == 0)
  92. do_timer(regs);
  93. #ifdef CONFIG_SMP
  94. {
  95. int user = user_mode(regs);
  96. /*
  97.  * update_process_times() expects us to have done irq_enter().
  98.  * Besides, if we don't timer interrupts ignore the global
  99.  * interrupt lock, which is the WrongThing (tm) to do.
  100.  * Picked from i386 code.
  101.  */
  102. irq_enter(cpu, 0);
  103. update_process_times(user);
  104. irq_exit(cpu, 0);
  105. }
  106. #endif /* CONFIG_SMP */
  107. /*
  108.  * If we have an externally synchronized Linux clock, then update
  109.  * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
  110.  * called as close as possible to when a second starts.
  111.  */
  112. if ((time_status & STA_UNSYNC) == 0 &&
  113.     xtime.tv_sec > last_rtc_update + 660) {
  114. if (xtime.tv_usec >= 1000000 - ((unsigned) tick) / 2) {
  115. if (set_rtc_mmss(xtime.tv_sec + 1) == 0)
  116. last_rtc_update = xtime.tv_sec;
  117. else    
  118. last_rtc_update = xtime.tv_sec - 600;
  119. } else if (xtime.tv_usec <= ((unsigned) tick) / 2) {
  120. if (set_rtc_mmss(xtime.tv_sec) == 0)
  121. last_rtc_update = xtime.tv_sec;
  122. else    
  123. last_rtc_update = xtime.tv_sec - 600;
  124. }
  125.         }
  126. write_unlock(&xtime_lock);
  127. if (softirq_pending(cpu))
  128. do_softirq();
  129. }
  130. unsigned long inline do_gettimeoffset(void)
  131. {
  132. unsigned long ct_cur1;
  133. ct_cur1 = REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT) + CYCLES_PER_JIFFY;
  134. return (ct_cur1 - ct_cur[0]) * NSEC_PER_CYCLE / 1000;
  135. }
  136. void do_gettimeofday(struct timeval *tv)
  137. {
  138. unsigned long flags;
  139. unsigned long usec, sec;
  140. read_lock_irqsave(&xtime_lock, flags);
  141. usec = do_gettimeoffset();
  142. {
  143. unsigned long lost = jiffies - wall_jiffies;
  144. if (lost)
  145. usec += lost * (1000000 / HZ);
  146. }
  147. sec = xtime.tv_sec;
  148. usec += xtime.tv_usec;
  149. read_unlock_irqrestore(&xtime_lock, flags);
  150. while (usec >= 1000000) {
  151. usec -= 1000000;
  152. sec++;
  153. }
  154. tv->tv_sec = sec;
  155. tv->tv_usec = usec;
  156. }
  157. void do_settimeofday(struct timeval *tv)
  158. {
  159. write_lock_irq(&xtime_lock);
  160. tv->tv_usec -= do_gettimeoffset();
  161. tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ);
  162. while (tv->tv_usec < 0) {
  163. tv->tv_usec += 1000000;
  164. tv->tv_sec--;
  165. }
  166. xtime = *tv;
  167. time_adjust = 0; /* stop active adjtime() */
  168. time_status |= STA_UNSYNC;
  169. time_maxerror = NTP_PHASE_LIMIT;
  170. time_esterror = NTP_PHASE_LIMIT;
  171. write_unlock_irq(&xtime_lock);
  172. }
  173. /* Includes for ioc3_init().  */
  174. #include <asm/sn/types.h>
  175. #include <asm/sn/sn0/addrs.h>
  176. #include <asm/sn/sn0/hubni.h>
  177. #include <asm/sn/sn0/hubio.h>
  178. #include <asm/pci/bridge.h>
  179. static __init unsigned long get_m48t35_time(void)
  180. {
  181.         unsigned int year, month, date, hour, min, sec;
  182. struct m48t35_rtc *rtc;
  183. nasid_t nid;
  184. nid = get_nasid();
  185. rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base + 
  186. IOC3_BYTEBUS_DEV0);
  187. rtc->control |= M48T35_RTC_READ;
  188. sec = rtc->sec;
  189. min = rtc->min;
  190. hour = rtc->hour;
  191. date = rtc->date;
  192. month = rtc->month;
  193. year = rtc->year;
  194. rtc->control &= ~M48T35_RTC_READ;
  195.         BCD_TO_BIN(sec);
  196.         BCD_TO_BIN(min);
  197.         BCD_TO_BIN(hour);
  198.         BCD_TO_BIN(date);
  199.         BCD_TO_BIN(month);
  200.         BCD_TO_BIN(year);
  201.         year += 1970;
  202.         return mktime(year, month, date, hour, min, sec);
  203. }
  204. void __init time_init(void)
  205. {
  206. xtime.tv_sec = get_m48t35_time();
  207. xtime.tv_usec = 0;
  208. }
  209. void __init cpu_time_init(void)
  210. {
  211. lboard_t *board;
  212. klcpu_t *cpu;
  213. int cpuid;
  214. /* Don't use ARCS.  ARCS is fragile.  Klconfig is simple and sane.  */
  215. board = find_lboard(KL_CONFIG_INFO(get_nasid()), KLTYPE_IP27);
  216. if (!board)
  217. panic("Can't find board info for myself.");
  218. cpuid = LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX;
  219. cpu = (klcpu_t *) KLCF_COMP(board, cpuid);
  220. if (!cpu)
  221. panic("No information about myself?");
  222. printk("CPU %d clock is %dMHz.n", smp_processor_id(), cpu->cpu_speed);
  223. set_cp0_status(SRB_TIMOCLK, SRB_TIMOCLK);
  224. }
  225. void __init hub_rtc_init(cnodeid_t cnode)
  226. {
  227. /*
  228.  * We only need to initialize the current node.
  229.  * If this is not the current node then it is a cpuless
  230.  * node and timeouts will not happen there.
  231.  */
  232. if (get_compact_nodeid() == cnode) {
  233. int cpu = smp_processor_id();
  234. LOCAL_HUB_S(PI_RT_EN_A, 1);
  235. LOCAL_HUB_S(PI_RT_EN_B, 1);
  236. LOCAL_HUB_S(PI_PROF_EN_A, 0);
  237. LOCAL_HUB_S(PI_PROF_EN_B, 0);
  238. ct_cur[cpu] = CYCLES_PER_JIFFY;
  239. LOCAL_HUB_S(PI_RT_COMPARE_A, ct_cur[cpu]);
  240. LOCAL_HUB_S(PI_RT_COUNT, 0);
  241. LOCAL_HUB_S(PI_RT_PEND_A, 0);
  242. LOCAL_HUB_S(PI_RT_COMPARE_B, ct_cur[cpu]);
  243. LOCAL_HUB_S(PI_RT_COUNT, 0);
  244. LOCAL_HUB_S(PI_RT_PEND_B, 0);
  245. }
  246. }