aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/macintosh/via-pmu.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2007-12-19 06:45:31 -0500
committerPaul Mackerras <paulus@samba.org>2007-12-19 06:45:31 -0500
commit887ef35ae4eb269839e0f296b132edc15477db1c (patch)
treea4912dbf2aadf46c8ecee495bb9a854727b99e5c /drivers/macintosh/via-pmu.c
parent98f6740ea6d532550c4010960fcead2c32bd56f5 (diff)
[POWERPC] Fix sleep on powerbook 3400
Sleep on the powerbook 3400 has been broken since the change that made powerbook_sleep_3400 call pmac_suspend_devices(), which disables interrupts. There are a couple of loops in powerbook_sleep_3400 that depend on interrupts being enabled, and in fact it has to have interrupts enabled at the point of going to sleep since it is an interrupt from the PMU that wakes it up. This fixes it by using pmu_wait_complete() instead of a spinloop, and by explicitly enabling interrupts before putting the CPU into sleep mode (which is OK since all interrupts except the PMU interrupt have been disabled at the interrupt controller by this stage). This changes the logic so that it keeps putting the CPU into sleep mode until the completion of the interrupt transaction from the PMU that signals the end of sleep. Also, we now call pmu_unlock() before sleep so that the via_pmu_interrupt() code can process the interrupt event from the PMU properly. Now that generic code saves and restores PCI state, it is no longer necessary to do that here. Thus pbook_pci_save/restore and related functions are no longer necessary, so this removes them. Lastly, this moves the ioremap of the memory controller to init code rather than doing it on every sleep/wakeup cycle. Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'drivers/macintosh/via-pmu.c')
-rw-r--r--drivers/macintosh/via-pmu.c172
1 files changed, 36 insertions, 136 deletions
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 6df3f3503e5b..0e233185ad14 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -202,6 +202,12 @@ static int proc_read_options(char *page, char **start, off_t off,
202static int proc_write_options(struct file *file, const char __user *buffer, 202static int proc_write_options(struct file *file, const char __user *buffer,
203 unsigned long count, void *data); 203 unsigned long count, void *data);
204 204
205#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
206static void powerbook_sleep_init_3400(void);
207#else
208#define powerbook_sleep_init_3400() do { } while (0)
209#endif
210
205#ifdef CONFIG_ADB 211#ifdef CONFIG_ADB
206struct adb_driver via_pmu_driver = { 212struct adb_driver via_pmu_driver = {
207 "PMU", 213 "PMU",
@@ -449,6 +455,10 @@ static int __init via_pmu_start(void)
449 pmu_poll(); 455 pmu_poll();
450 } while (pmu_state != idle); 456 } while (pmu_state != idle);
451 457
458 /* Do allocations and ioremaps that will be needed for sleep */
459 if (pmu_kind == PMU_OHARE_BASED)
460 powerbook_sleep_init_3400();
461
452 return 0; 462 return 0;
453} 463}
454 464
@@ -1719,108 +1729,6 @@ pmu_present(void)
1719} 1729}
1720 1730
1721#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32) 1731#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
1722/*
1723 * This struct is used to store config register values for
1724 * PCI devices which may get powered off when we sleep.
1725 */
1726static struct pci_save {
1727 u16 command;
1728 u16 cache_lat;
1729 u16 intr;
1730 u32 rom_address;
1731} *pbook_pci_saves;
1732static int pbook_npci_saves;
1733
1734static void
1735pbook_alloc_pci_save(void)
1736{
1737 int npci;
1738 struct pci_dev *pd = NULL;
1739
1740 npci = 0;
1741 while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
1742 ++npci;
1743 }
1744 if (npci == 0)
1745 return;
1746 pbook_pci_saves = (struct pci_save *)
1747 kmalloc(npci * sizeof(struct pci_save), GFP_KERNEL);
1748 pbook_npci_saves = npci;
1749}
1750
1751static void
1752pbook_free_pci_save(void)
1753{
1754 if (pbook_pci_saves == NULL)
1755 return;
1756 kfree(pbook_pci_saves);
1757 pbook_pci_saves = NULL;
1758 pbook_npci_saves = 0;
1759}
1760
1761static void
1762pbook_pci_save(void)
1763{
1764 struct pci_save *ps = pbook_pci_saves;
1765 struct pci_dev *pd = NULL;
1766 int npci = pbook_npci_saves;
1767
1768 if (ps == NULL)
1769 return;
1770
1771 while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
1772 if (npci-- == 0) {
1773 pci_dev_put(pd);
1774 return;
1775 }
1776 pci_read_config_word(pd, PCI_COMMAND, &ps->command);
1777 pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
1778 pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
1779 pci_read_config_dword(pd, PCI_ROM_ADDRESS, &ps->rom_address);
1780 ++ps;
1781 }
1782}
1783
1784/* For this to work, we must take care of a few things: If gmac was enabled
1785 * during boot, it will be in the pci dev list. If it's disabled at this point
1786 * (and it will probably be), then you can't access it's config space.
1787 */
1788static void
1789pbook_pci_restore(void)
1790{
1791 u16 cmd;
1792 struct pci_save *ps = pbook_pci_saves - 1;
1793 struct pci_dev *pd = NULL;
1794 int npci = pbook_npci_saves;
1795 int j;
1796
1797 while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
1798 if (npci-- == 0)
1799 return;
1800 ps++;
1801 if (ps->command == 0)
1802 continue;
1803 pci_read_config_word(pd, PCI_COMMAND, &cmd);
1804 if ((ps->command & ~cmd) == 0)
1805 continue;
1806 switch (pd->hdr_type) {
1807 case PCI_HEADER_TYPE_NORMAL:
1808 for (j = 0; j < 6; ++j)
1809 pci_write_config_dword(pd,
1810 PCI_BASE_ADDRESS_0 + j*4,
1811 pd->resource[j].start);
1812 pci_write_config_dword(pd, PCI_ROM_ADDRESS,
1813 ps->rom_address);
1814 pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
1815 ps->cache_lat);
1816 pci_write_config_word(pd, PCI_INTERRUPT_LINE,
1817 ps->intr);
1818 pci_write_config_word(pd, PCI_COMMAND, ps->command);
1819 break;
1820 }
1821 }
1822}
1823
1824#ifdef DEBUG_SLEEP 1732#ifdef DEBUG_SLEEP
1825/* N.B. This doesn't work on the 3400 */ 1733/* N.B. This doesn't work on the 3400 */
1826void 1734void
@@ -2200,37 +2108,34 @@ powerbook_sleep_Core99(void)
2200#define PB3400_MEM_CTRL 0xf8000000 2108#define PB3400_MEM_CTRL 0xf8000000
2201#define PB3400_MEM_CTRL_SLEEP 0x70 2109#define PB3400_MEM_CTRL_SLEEP 0x70
2202 2110
2203static int 2111static void __iomem *pb3400_mem_ctrl;
2204powerbook_sleep_3400(void) 2112
2113static void powerbook_sleep_init_3400(void)
2114{
2115 /* map in the memory controller registers */
2116 pb3400_mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100);
2117 if (pb3400_mem_ctrl == NULL)
2118 printk(KERN_WARNING "ioremap failed: sleep won't be possible");
2119}
2120
2121static int powerbook_sleep_3400(void)
2205{ 2122{
2206 int ret, i, x; 2123 int ret, i, x;
2207 unsigned int hid0; 2124 unsigned int hid0;
2208 unsigned long p; 2125 unsigned long msr;
2209 struct adb_request sleep_req; 2126 struct adb_request sleep_req;
2210 void __iomem *mem_ctrl;
2211 unsigned int __iomem *mem_ctrl_sleep; 2127 unsigned int __iomem *mem_ctrl_sleep;
2212 2128
2213 /* first map in the memory controller registers */ 2129 if (pb3400_mem_ctrl == NULL)
2214 mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100);
2215 if (mem_ctrl == NULL) {
2216 printk("powerbook_sleep_3400: ioremap failed\n");
2217 return -ENOMEM; 2130 return -ENOMEM;
2218 } 2131 mem_ctrl_sleep = pb3400_mem_ctrl + PB3400_MEM_CTRL_SLEEP;
2219 mem_ctrl_sleep = mem_ctrl + PB3400_MEM_CTRL_SLEEP;
2220
2221 /* Allocate room for PCI save */
2222 pbook_alloc_pci_save();
2223 2132
2224 ret = pmac_suspend_devices(); 2133 ret = pmac_suspend_devices();
2225 if (ret) { 2134 if (ret) {
2226 pbook_free_pci_save();
2227 printk(KERN_ERR "Sleep rejected by devices\n"); 2135 printk(KERN_ERR "Sleep rejected by devices\n");
2228 return ret; 2136 return ret;
2229 } 2137 }
2230 2138
2231 /* Save the state of PCI config space for some slots */
2232 pbook_pci_save();
2233
2234 /* Set the memory controller to keep the memory refreshed 2139 /* Set the memory controller to keep the memory refreshed
2235 while we're asleep */ 2140 while we're asleep */
2236 for (i = 0x403f; i >= 0x4000; --i) { 2141 for (i = 0x403f; i >= 0x4000; --i) {
@@ -2244,36 +2149,31 @@ powerbook_sleep_3400(void)
2244 2149
2245 /* Ask the PMU to put us to sleep */ 2150 /* Ask the PMU to put us to sleep */
2246 pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T'); 2151 pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
2247 while (!sleep_req.complete) 2152 pmu_wait_complete(&sleep_req);
2248 mb(); 2153 pmu_unlock();
2249 2154
2250 pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1); 2155 pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 1);
2251 2156
2252 /* displacement-flush the L2 cache - necessary? */
2253 for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)
2254 i = *(volatile int *)p;
2255 asleep = 1; 2157 asleep = 1;
2256 2158
2257 /* Put the CPU into sleep mode */ 2159 /* Put the CPU into sleep mode */
2258 hid0 = mfspr(SPRN_HID0); 2160 hid0 = mfspr(SPRN_HID0);
2259 hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; 2161 hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
2260 mtspr(SPRN_HID0, hid0); 2162 mtspr(SPRN_HID0, hid0);
2261 mtmsr(mfmsr() | MSR_POW | MSR_EE); 2163 local_irq_enable();
2262 udelay(10); 2164 msr = mfmsr() | MSR_POW;
2165 while (asleep) {
2166 mb();
2167 mtmsr(msr);
2168 isync();
2169 }
2170 local_irq_disable();
2263 2171
2264 /* OK, we're awake again, start restoring things */ 2172 /* OK, we're awake again, start restoring things */
2265 out_be32(mem_ctrl_sleep, 0x3f); 2173 out_be32(mem_ctrl_sleep, 0x3f);
2266 pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0); 2174 pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0);
2267 pbook_pci_restore();
2268 pmu_unlock();
2269
2270 /* wait for the PMU interrupt sequence to complete */
2271 while (asleep)
2272 mb();
2273 2175
2274 pmac_wakeup_devices(); 2176 pmac_wakeup_devices();
2275 pbook_free_pci_save();
2276 iounmap(mem_ctrl);
2277 2177
2278 return 0; 2178 return 0;
2279} 2179}