diff options
Diffstat (limited to 'arch/ppc64')
-rw-r--r-- | arch/ppc64/kernel/mf.c | 85 | ||||
-rw-r--r-- | arch/ppc64/kernel/pmac_smp.c | 28 | ||||
-rw-r--r-- | arch/ppc64/kernel/prom_init.c | 50 | ||||
-rw-r--r-- | arch/ppc64/kernel/rtc.c | 39 | ||||
-rw-r--r-- | arch/ppc64/kernel/time.c | 1 |
5 files changed, 137 insertions, 66 deletions
diff --git a/arch/ppc64/kernel/mf.c b/arch/ppc64/kernel/mf.c index 1bd52ece497c..5aca7e8005a8 100644 --- a/arch/ppc64/kernel/mf.c +++ b/arch/ppc64/kernel/mf.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * mf.c | 2 | * mf.c |
3 | * Copyright (C) 2001 Troy D. Armstrong IBM Corporation | 3 | * Copyright (C) 2001 Troy D. Armstrong IBM Corporation |
4 | * Copyright (C) 2004 Stephen Rothwell IBM Corporation | 4 | * Copyright (C) 2004-2005 Stephen Rothwell IBM Corporation |
5 | * | 5 | * |
6 | * This modules exists as an interface between a Linux secondary partition | 6 | * This modules exists as an interface between a Linux secondary partition |
7 | * running on an iSeries and the primary partition's Virtual Service | 7 | * running on an iSeries and the primary partition's Virtual Service |
@@ -36,10 +36,12 @@ | |||
36 | 36 | ||
37 | #include <asm/time.h> | 37 | #include <asm/time.h> |
38 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
39 | #include <asm/paca.h> | ||
39 | #include <asm/iSeries/vio.h> | 40 | #include <asm/iSeries/vio.h> |
40 | #include <asm/iSeries/mf.h> | 41 | #include <asm/iSeries/mf.h> |
41 | #include <asm/iSeries/HvLpConfig.h> | 42 | #include <asm/iSeries/HvLpConfig.h> |
42 | #include <asm/iSeries/ItSpCommArea.h> | 43 | #include <asm/iSeries/ItSpCommArea.h> |
44 | #include <asm/iSeries/ItLpQueue.h> | ||
43 | 45 | ||
44 | /* | 46 | /* |
45 | * This is the structure layout for the Machine Facilites LPAR event | 47 | * This is the structure layout for the Machine Facilites LPAR event |
@@ -696,36 +698,23 @@ static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) | |||
696 | complete(&rtc->com); | 698 | complete(&rtc->com); |
697 | } | 699 | } |
698 | 700 | ||
699 | int mf_get_rtc(struct rtc_time *tm) | 701 | static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm) |
700 | { | 702 | { |
701 | struct ce_msg_comp_data ce_complete; | ||
702 | struct rtc_time_data rtc_data; | ||
703 | int rc; | ||
704 | |||
705 | memset(&ce_complete, 0, sizeof(ce_complete)); | ||
706 | memset(&rtc_data, 0, sizeof(rtc_data)); | ||
707 | init_completion(&rtc_data.com); | ||
708 | ce_complete.handler = &get_rtc_time_complete; | ||
709 | ce_complete.token = &rtc_data; | ||
710 | rc = signal_ce_msg_simple(0x40, &ce_complete); | ||
711 | if (rc) | ||
712 | return rc; | ||
713 | wait_for_completion(&rtc_data.com); | ||
714 | tm->tm_wday = 0; | 703 | tm->tm_wday = 0; |
715 | tm->tm_yday = 0; | 704 | tm->tm_yday = 0; |
716 | tm->tm_isdst = 0; | 705 | tm->tm_isdst = 0; |
717 | if (rtc_data.rc) { | 706 | if (rc) { |
718 | tm->tm_sec = 0; | 707 | tm->tm_sec = 0; |
719 | tm->tm_min = 0; | 708 | tm->tm_min = 0; |
720 | tm->tm_hour = 0; | 709 | tm->tm_hour = 0; |
721 | tm->tm_mday = 15; | 710 | tm->tm_mday = 15; |
722 | tm->tm_mon = 5; | 711 | tm->tm_mon = 5; |
723 | tm->tm_year = 52; | 712 | tm->tm_year = 52; |
724 | return rtc_data.rc; | 713 | return rc; |
725 | } | 714 | } |
726 | 715 | ||
727 | if ((rtc_data.ce_msg.ce_msg[2] == 0xa9) || | 716 | if ((ce_msg[2] == 0xa9) || |
728 | (rtc_data.ce_msg.ce_msg[2] == 0xaf)) { | 717 | (ce_msg[2] == 0xaf)) { |
729 | /* TOD clock is not set */ | 718 | /* TOD clock is not set */ |
730 | tm->tm_sec = 1; | 719 | tm->tm_sec = 1; |
731 | tm->tm_min = 1; | 720 | tm->tm_min = 1; |
@@ -736,7 +725,6 @@ int mf_get_rtc(struct rtc_time *tm) | |||
736 | mf_set_rtc(tm); | 725 | mf_set_rtc(tm); |
737 | } | 726 | } |
738 | { | 727 | { |
739 | u8 *ce_msg = rtc_data.ce_msg.ce_msg; | ||
740 | u8 year = ce_msg[5]; | 728 | u8 year = ce_msg[5]; |
741 | u8 sec = ce_msg[6]; | 729 | u8 sec = ce_msg[6]; |
742 | u8 min = ce_msg[7]; | 730 | u8 min = ce_msg[7]; |
@@ -765,6 +753,63 @@ int mf_get_rtc(struct rtc_time *tm) | |||
765 | return 0; | 753 | return 0; |
766 | } | 754 | } |
767 | 755 | ||
756 | int mf_get_rtc(struct rtc_time *tm) | ||
757 | { | ||
758 | struct ce_msg_comp_data ce_complete; | ||
759 | struct rtc_time_data rtc_data; | ||
760 | int rc; | ||
761 | |||
762 | memset(&ce_complete, 0, sizeof(ce_complete)); | ||
763 | memset(&rtc_data, 0, sizeof(rtc_data)); | ||
764 | init_completion(&rtc_data.com); | ||
765 | ce_complete.handler = &get_rtc_time_complete; | ||
766 | ce_complete.token = &rtc_data; | ||
767 | rc = signal_ce_msg_simple(0x40, &ce_complete); | ||
768 | if (rc) | ||
769 | return rc; | ||
770 | wait_for_completion(&rtc_data.com); | ||
771 | return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); | ||
772 | } | ||
773 | |||
774 | struct boot_rtc_time_data { | ||
775 | int busy; | ||
776 | struct ce_msg_data ce_msg; | ||
777 | int rc; | ||
778 | }; | ||
779 | |||
780 | static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) | ||
781 | { | ||
782 | struct boot_rtc_time_data *rtc = token; | ||
783 | |||
784 | memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); | ||
785 | rtc->rc = 0; | ||
786 | rtc->busy = 0; | ||
787 | } | ||
788 | |||
789 | int mf_get_boot_rtc(struct rtc_time *tm) | ||
790 | { | ||
791 | struct ce_msg_comp_data ce_complete; | ||
792 | struct boot_rtc_time_data rtc_data; | ||
793 | int rc; | ||
794 | |||
795 | memset(&ce_complete, 0, sizeof(ce_complete)); | ||
796 | memset(&rtc_data, 0, sizeof(rtc_data)); | ||
797 | rtc_data.busy = 1; | ||
798 | ce_complete.handler = &get_boot_rtc_time_complete; | ||
799 | ce_complete.token = &rtc_data; | ||
800 | rc = signal_ce_msg_simple(0x40, &ce_complete); | ||
801 | if (rc) | ||
802 | return rc; | ||
803 | /* We need to poll here as we are not yet taking interrupts */ | ||
804 | while (rtc_data.busy) { | ||
805 | extern unsigned long lpevent_count; | ||
806 | struct ItLpQueue *lpq = get_paca()->lpqueue_ptr; | ||
807 | if (lpq && ItLpQueue_isLpIntPending(lpq)) | ||
808 | lpevent_count += ItLpQueue_process(lpq, NULL); | ||
809 | } | ||
810 | return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); | ||
811 | } | ||
812 | |||
768 | int mf_set_rtc(struct rtc_time *tm) | 813 | int mf_set_rtc(struct rtc_time *tm) |
769 | { | 814 | { |
770 | char ce_time[12]; | 815 | char ce_time[12]; |
diff --git a/arch/ppc64/kernel/pmac_smp.c b/arch/ppc64/kernel/pmac_smp.c index c27588ede2fe..a23de37227bf 100644 --- a/arch/ppc64/kernel/pmac_smp.c +++ b/arch/ppc64/kernel/pmac_smp.c | |||
@@ -68,6 +68,7 @@ extern struct smp_ops_t *smp_ops; | |||
68 | 68 | ||
69 | static void (*pmac_tb_freeze)(int freeze); | 69 | static void (*pmac_tb_freeze)(int freeze); |
70 | static struct device_node *pmac_tb_clock_chip_host; | 70 | static struct device_node *pmac_tb_clock_chip_host; |
71 | static u8 pmac_tb_pulsar_addr; | ||
71 | static DEFINE_SPINLOCK(timebase_lock); | 72 | static DEFINE_SPINLOCK(timebase_lock); |
72 | static unsigned long timebase; | 73 | static unsigned long timebase; |
73 | 74 | ||
@@ -106,12 +107,9 @@ static void smp_core99_pulsar_tb_freeze(int freeze) | |||
106 | u8 data; | 107 | u8 data; |
107 | int rc; | 108 | int rc; |
108 | 109 | ||
109 | /* Strangely, the device-tree says address is 0xd2, but darwin | ||
110 | * accesses 0xd0 ... | ||
111 | */ | ||
112 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); | 110 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_combined); |
113 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | 111 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, |
114 | 0xd4 | pmac_low_i2c_read, | 112 | pmac_tb_pulsar_addr | pmac_low_i2c_read, |
115 | 0x2e, &data, 1); | 113 | 0x2e, &data, 1); |
116 | if (rc != 0) | 114 | if (rc != 0) |
117 | goto bail; | 115 | goto bail; |
@@ -120,7 +118,7 @@ static void smp_core99_pulsar_tb_freeze(int freeze) | |||
120 | 118 | ||
121 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); | 119 | pmac_low_i2c_setmode(pmac_tb_clock_chip_host, pmac_low_i2c_mode_stdsub); |
122 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, | 120 | rc = pmac_low_i2c_xfer(pmac_tb_clock_chip_host, |
123 | 0xd4 | pmac_low_i2c_write, | 121 | pmac_tb_pulsar_addr | pmac_low_i2c_write, |
124 | 0x2e, &data, 1); | 122 | 0x2e, &data, 1); |
125 | bail: | 123 | bail: |
126 | if (rc != 0) { | 124 | if (rc != 0) { |
@@ -185,6 +183,12 @@ static int __init smp_core99_probe(void) | |||
185 | if (ncpus <= 1) | 183 | if (ncpus <= 1) |
186 | return 1; | 184 | return 1; |
187 | 185 | ||
186 | /* HW sync only on these platforms */ | ||
187 | if (!machine_is_compatible("PowerMac7,2") && | ||
188 | !machine_is_compatible("PowerMac7,3") && | ||
189 | !machine_is_compatible("RackMac3,1")) | ||
190 | goto nohwsync; | ||
191 | |||
188 | /* Look for the clock chip */ | 192 | /* Look for the clock chip */ |
189 | for (cc = NULL; (cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL;) { | 193 | for (cc = NULL; (cc = of_find_node_by_name(cc, "i2c-hwclock")) != NULL;) { |
190 | struct device_node *p = of_get_parent(cc); | 194 | struct device_node *p = of_get_parent(cc); |
@@ -198,11 +202,18 @@ static int __init smp_core99_probe(void) | |||
198 | goto next; | 202 | goto next; |
199 | switch (*reg) { | 203 | switch (*reg) { |
200 | case 0xd2: | 204 | case 0xd2: |
201 | pmac_tb_freeze = smp_core99_cypress_tb_freeze; | 205 | if (device_is_compatible(cc, "pulsar-legacy-slewing")) { |
202 | printk(KERN_INFO "Timebase clock is Cypress chip\n"); | 206 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; |
207 | pmac_tb_pulsar_addr = 0xd2; | ||
208 | printk(KERN_INFO "Timebase clock is Pulsar chip\n"); | ||
209 | } else if (device_is_compatible(cc, "cy28508")) { | ||
210 | pmac_tb_freeze = smp_core99_cypress_tb_freeze; | ||
211 | printk(KERN_INFO "Timebase clock is Cypress chip\n"); | ||
212 | } | ||
203 | break; | 213 | break; |
204 | case 0xd4: | 214 | case 0xd4: |
205 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; | 215 | pmac_tb_freeze = smp_core99_pulsar_tb_freeze; |
216 | pmac_tb_pulsar_addr = 0xd4; | ||
206 | printk(KERN_INFO "Timebase clock is Pulsar chip\n"); | 217 | printk(KERN_INFO "Timebase clock is Pulsar chip\n"); |
207 | break; | 218 | break; |
208 | } | 219 | } |
@@ -210,12 +221,15 @@ static int __init smp_core99_probe(void) | |||
210 | pmac_tb_clock_chip_host = p; | 221 | pmac_tb_clock_chip_host = p; |
211 | smp_ops->give_timebase = smp_core99_give_timebase; | 222 | smp_ops->give_timebase = smp_core99_give_timebase; |
212 | smp_ops->take_timebase = smp_core99_take_timebase; | 223 | smp_ops->take_timebase = smp_core99_take_timebase; |
224 | of_node_put(cc); | ||
225 | of_node_put(p); | ||
213 | break; | 226 | break; |
214 | } | 227 | } |
215 | next: | 228 | next: |
216 | of_node_put(p); | 229 | of_node_put(p); |
217 | } | 230 | } |
218 | 231 | ||
232 | nohwsync: | ||
219 | mpic_request_ipis(); | 233 | mpic_request_ipis(); |
220 | 234 | ||
221 | return ncpus; | 235 | return ncpus; |
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index 35ec42de962e..bc53967a8643 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c | |||
@@ -1750,7 +1750,44 @@ static void __init flatten_device_tree(void) | |||
1750 | prom_printf("Device tree struct 0x%x -> 0x%x\n", | 1750 | prom_printf("Device tree struct 0x%x -> 0x%x\n", |
1751 | RELOC(dt_struct_start), RELOC(dt_struct_end)); | 1751 | RELOC(dt_struct_start), RELOC(dt_struct_end)); |
1752 | 1752 | ||
1753 | } | 1753 | } |
1754 | |||
1755 | |||
1756 | static void __init fixup_device_tree(void) | ||
1757 | { | ||
1758 | unsigned long offset = reloc_offset(); | ||
1759 | phandle u3, i2c, mpic; | ||
1760 | u32 u3_rev; | ||
1761 | u32 interrupts[2]; | ||
1762 | u32 parent; | ||
1763 | |||
1764 | /* Some G5s have a missing interrupt definition, fix it up here */ | ||
1765 | u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000")); | ||
1766 | if ((long)u3 <= 0) | ||
1767 | return; | ||
1768 | i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000")); | ||
1769 | if ((long)i2c <= 0) | ||
1770 | return; | ||
1771 | mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000")); | ||
1772 | if ((long)mpic <= 0) | ||
1773 | return; | ||
1774 | |||
1775 | /* check if proper rev of u3 */ | ||
1776 | if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) <= 0) | ||
1777 | return; | ||
1778 | if (u3_rev != 0x35) | ||
1779 | return; | ||
1780 | /* does it need fixup ? */ | ||
1781 | if (prom_getproplen(i2c, "interrupts") > 0) | ||
1782 | return; | ||
1783 | /* interrupt on this revision of u3 is number 0 and level */ | ||
1784 | interrupts[0] = 0; | ||
1785 | interrupts[1] = 1; | ||
1786 | prom_setprop(i2c, "interrupts", &interrupts, sizeof(interrupts)); | ||
1787 | parent = (u32)mpic; | ||
1788 | prom_setprop(i2c, "interrupt-parent", &parent, sizeof(parent)); | ||
1789 | } | ||
1790 | |||
1754 | 1791 | ||
1755 | static void __init prom_find_boot_cpu(void) | 1792 | static void __init prom_find_boot_cpu(void) |
1756 | { | 1793 | { |
@@ -1844,6 +1881,12 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long | |||
1844 | &getprop_rval, sizeof(getprop_rval)); | 1881 | &getprop_rval, sizeof(getprop_rval)); |
1845 | 1882 | ||
1846 | /* | 1883 | /* |
1884 | * On pSeries, inform the firmware about our capabilities | ||
1885 | */ | ||
1886 | if (RELOC(of_platform) & PLATFORM_PSERIES) | ||
1887 | prom_send_capabilities(); | ||
1888 | |||
1889 | /* | ||
1847 | * On pSeries, copy the CPU hold code | 1890 | * On pSeries, copy the CPU hold code |
1848 | */ | 1891 | */ |
1849 | if (RELOC(of_platform) & PLATFORM_PSERIES) | 1892 | if (RELOC(of_platform) & PLATFORM_PSERIES) |
@@ -1920,6 +1963,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long | |||
1920 | } | 1963 | } |
1921 | 1964 | ||
1922 | /* | 1965 | /* |
1966 | * Fixup any known bugs in the device-tree | ||
1967 | */ | ||
1968 | fixup_device_tree(); | ||
1969 | |||
1970 | /* | ||
1923 | * Now finally create the flattened device-tree | 1971 | * Now finally create the flattened device-tree |
1924 | */ | 1972 | */ |
1925 | prom_printf("copying OF device tree ...\n"); | 1973 | prom_printf("copying OF device tree ...\n"); |
diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c index 3e70b91375fc..67989055a9fe 100644 --- a/arch/ppc64/kernel/rtc.c +++ b/arch/ppc64/kernel/rtc.c | |||
@@ -292,47 +292,10 @@ int iSeries_set_rtc_time(struct rtc_time *tm) | |||
292 | 292 | ||
293 | void iSeries_get_boot_time(struct rtc_time *tm) | 293 | void iSeries_get_boot_time(struct rtc_time *tm) |
294 | { | 294 | { |
295 | unsigned long time; | ||
296 | static unsigned long lastsec = 1; | ||
297 | |||
298 | u32 dataWord1 = *((u32 *)(&xSpCommArea.xBcdTimeAtIplStart)); | ||
299 | u32 dataWord2 = *(((u32 *)&(xSpCommArea.xBcdTimeAtIplStart)) + 1); | ||
300 | int year = 1970; | ||
301 | int year1 = ( dataWord1 >> 24 ) & 0x000000FF; | ||
302 | int year2 = ( dataWord1 >> 16 ) & 0x000000FF; | ||
303 | int sec = ( dataWord1 >> 8 ) & 0x000000FF; | ||
304 | int min = dataWord1 & 0x000000FF; | ||
305 | int hour = ( dataWord2 >> 24 ) & 0x000000FF; | ||
306 | int day = ( dataWord2 >> 8 ) & 0x000000FF; | ||
307 | int mon = dataWord2 & 0x000000FF; | ||
308 | |||
309 | if ( piranha_simulator ) | 295 | if ( piranha_simulator ) |
310 | return; | 296 | return; |
311 | 297 | ||
312 | BCD_TO_BIN(sec); | 298 | mf_get_boot_rtc(tm); |
313 | BCD_TO_BIN(min); | ||
314 | BCD_TO_BIN(hour); | ||
315 | BCD_TO_BIN(day); | ||
316 | BCD_TO_BIN(mon); | ||
317 | BCD_TO_BIN(year1); | ||
318 | BCD_TO_BIN(year2); | ||
319 | year = year1 * 100 + year2; | ||
320 | |||
321 | time = mktime(year, mon, day, hour, min, sec); | ||
322 | time += ( jiffies / HZ ); | ||
323 | |||
324 | /* Now THIS is a nasty hack! | ||
325 | * It ensures that the first two calls get different answers. | ||
326 | * That way the loop in init_time (time.c) will not think | ||
327 | * the clock is stuck. | ||
328 | */ | ||
329 | if ( lastsec ) { | ||
330 | time -= lastsec; | ||
331 | --lastsec; | ||
332 | } | ||
333 | |||
334 | to_tm(time, tm); | ||
335 | tm->tm_year -= 1900; | ||
336 | tm->tm_mon -= 1; | 299 | tm->tm_mon -= 1; |
337 | } | 300 | } |
338 | #endif | 301 | #endif |
diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index 772a465b49f9..3d54745108c7 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c | |||
@@ -515,6 +515,7 @@ void __init time_init(void) | |||
515 | do_gtod.varp = &do_gtod.vars[0]; | 515 | do_gtod.varp = &do_gtod.vars[0]; |
516 | do_gtod.var_idx = 0; | 516 | do_gtod.var_idx = 0; |
517 | do_gtod.varp->tb_orig_stamp = tb_last_stamp; | 517 | do_gtod.varp->tb_orig_stamp = tb_last_stamp; |
518 | get_paca()->next_jiffy_update_tb = tb_last_stamp + tb_ticks_per_jiffy; | ||
518 | do_gtod.varp->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; | 519 | do_gtod.varp->stamp_xsec = xtime.tv_sec * XSEC_PER_SEC; |
519 | do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; | 520 | do_gtod.tb_ticks_per_sec = tb_ticks_per_sec; |
520 | do_gtod.varp->tb_to_xs = tb_to_xs; | 521 | do_gtod.varp->tb_to_xs = tb_to_xs; |