From fc3167ecd6a68052e004c076e566aa6e4a55c72d Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 19 Jan 2009 13:45:28 +0100 Subject: [PATCH] --- yaml --- r: 131119 b: refs/heads/master c: 7a89bbc74937cd74a6bcf109cfc7c032109639be h: refs/heads/master i: 131117: 8fbf40c63bcff9606fc57e3a63b1048abe1c9b7f 131115: a938139d9798ead44d8f6d9e4d39c9b6604140c0 131111: 16cd1b434d3b383ea6d37ba0fe02fab999a80459 131103: 8825818c143a113ae04af19c74c8c97ffd7f2185 v: v3 --- [refs] | 2 +- trunk/drivers/video/aty/aty128fb.c | 25 ++++---- trunk/drivers/video/aty/atyfb_base.c | 20 ++----- trunk/drivers/video/aty/radeon_pm.c | 85 +++++++++++++++++++++------- trunk/drivers/video/aty/radeonfb.h | 2 + trunk/kernel/async.c | 4 +- 6 files changed, 85 insertions(+), 53 deletions(-) diff --git a/[refs] b/[refs] index 117087cf3cef..5196992a509e 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 1fb25cb8b83e85f5bf1a4adb3c9a254c4ce92405 +refs/heads/master: 7a89bbc74937cd74a6bcf109cfc7c032109639be diff --git a/trunk/drivers/video/aty/aty128fb.c b/trunk/drivers/video/aty/aty128fb.c index e6e299feb51b..fb2b0f5b23bd 100644 --- a/trunk/drivers/video/aty/aty128fb.c +++ b/trunk/drivers/video/aty/aty128fb.c @@ -2374,8 +2374,6 @@ static void aty128_set_suspend(struct aty128fb_par *par, int suspend) /* Set the chip into the appropriate suspend mode (we use D2, * D3 would require a complete re-initialisation of the chip, * including PCI config registers, clocks, AGP configuration, ...) - * - * For resume, the core will have already brought us back to D0 */ if (suspend) { /* Make sure CRTC2 is reset. Remove that the day we decide to @@ -2393,9 +2391,17 @@ static void aty128_set_suspend(struct aty128fb_par *par, int suspend) aty_st_le32(BUS_CNTL1, 0x00000010); aty_st_le32(MEM_POWER_MISC, 0x0c830000); mdelay(100); - + pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); /* Switch PCI power management to D2 */ - pci_set_power_state(pdev, PCI_D2); + pci_write_config_word(pdev, par->pm_reg+PCI_PM_CTRL, + (pwr_command & ~PCI_PM_CTRL_STATE_MASK) | 2); + pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); + } else { + /* Switch back PCI power management to D0 */ + mdelay(100); + pci_write_config_word(pdev, par->pm_reg+PCI_PM_CTRL, 0); + pci_read_config_word(pdev, par->pm_reg+PCI_PM_CTRL, &pwr_command); + mdelay(100); } } @@ -2404,12 +2410,6 @@ static int aty128_pci_suspend(struct pci_dev *pdev, pm_message_t state) struct fb_info *info = pci_get_drvdata(pdev); struct aty128fb_par *par = info->par; - /* Because we may change PCI D state ourselves, we need to - * first save the config space content so the core can - * restore it properly on resume. - */ - pci_save_state(pdev); - /* We don't do anything but D2, for now we return 0, but * we may want to change that. How do we know if the BIOS * can properly take care of D3 ? Also, with swsusp, we @@ -2476,11 +2476,6 @@ static int aty128_do_resume(struct pci_dev *pdev) if (pdev->dev.power.power_state.event == PM_EVENT_ON) return 0; - /* PCI state will have been restored by the core, so - * we should be in D0 now with our config space fully - * restored - */ - /* Wakeup chip */ aty128_set_suspend(par, 0); par->asleep = 0; diff --git a/trunk/drivers/video/aty/atyfb_base.c b/trunk/drivers/video/aty/atyfb_base.c index 1207c208a30b..1d6e16d346a5 100644 --- a/trunk/drivers/video/aty/atyfb_base.c +++ b/trunk/drivers/video/aty/atyfb_base.c @@ -1978,7 +1978,7 @@ static int aty_power_mgmt(int sleep, struct atyfb_par *par) return timeout ? 0 : -EIO; } -#endif /* CONFIG_PPC_PMAC */ +#endif static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) { @@ -2002,15 +2002,9 @@ static int atyfb_pci_suspend(struct pci_dev *pdev, pm_message_t state) par->asleep = 1; par->lock_blank = 1; - /* Because we may change PCI D state ourselves, we need to - * first save the config space content so the core can - * restore it properly on resume. - */ - pci_save_state(pdev); - #ifdef CONFIG_PPC_PMAC /* Set chip to "suspend" mode */ - if (machine_is(powermac) && aty_power_mgmt(1, par)) { + if (aty_power_mgmt(1, par)) { par->asleep = 0; par->lock_blank = 0; atyfb_blank(FB_BLANK_UNBLANK, info); @@ -2053,15 +2047,11 @@ static int atyfb_pci_resume(struct pci_dev *pdev) acquire_console_sem(); - /* PCI state will have been restored by the core, so - * we should be in D0 now with our config space fully - * restored - */ - #ifdef CONFIG_PPC_PMAC - if (machine_is(powermac) && - pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) + if (pdev->dev.power.power_state.event == 2) aty_power_mgmt(0, par); +#else + pci_set_power_state(pdev, PCI_D0); #endif aty_resume_chip(info); diff --git a/trunk/drivers/video/aty/radeon_pm.c b/trunk/drivers/video/aty/radeon_pm.c index ca5f0dc28546..c4ac2a032fcb 100644 --- a/trunk/drivers/video/aty/radeon_pm.c +++ b/trunk/drivers/video/aty/radeon_pm.c @@ -2509,7 +2509,9 @@ static void radeon_reinitialize_QW(struct radeonfb_info *rinfo) static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend) { + u16 pwr_cmd; u32 tmp; + int i; if (!rinfo->pm_reg) return; @@ -2555,14 +2557,32 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend) } } + for (i = 0; i < 64; ++i) + pci_read_config_dword(rinfo->pdev, i * 4, + &rinfo->cfg_save[i]); + /* Switch PCI power management to D2. */ pci_disable_device(rinfo->pdev); - pci_save_state(rinfo->pdev); - pci_set_power_state(rinfo->pdev, PCI_D2); + for (;;) { + pci_read_config_word( + rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, + &pwr_cmd); + if (pwr_cmd & 2) + break; + pci_write_config_word( + rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, + (pwr_cmd & ~PCI_PM_CTRL_STATE_MASK) | 2); + mdelay(500); + } } else { printk(KERN_DEBUG "radeonfb (%s): switching to D0 state...\n", pci_name(rinfo->pdev)); + /* Switch back PCI powermanagment to D0 */ + mdelay(200); + pci_write_config_word(rinfo->pdev, rinfo->pm_reg+PCI_PM_CTRL, 0); + mdelay(500); + if (rinfo->family <= CHIP_FAMILY_RV250) { /* Reset the SDRAM controller */ radeon_pm_full_reset_sdram(rinfo); @@ -2578,10 +2598,37 @@ static void radeon_set_suspend(struct radeonfb_info *rinfo, int suspend) } } +static int radeon_restore_pci_cfg(struct radeonfb_info *rinfo) +{ + int i; + static u32 radeon_cfg_after_resume[64]; + + for (i = 0; i < 64; ++i) + pci_read_config_dword(rinfo->pdev, i * 4, + &radeon_cfg_after_resume[i]); + + if (radeon_cfg_after_resume[PCI_BASE_ADDRESS_0/4] + == rinfo->cfg_save[PCI_BASE_ADDRESS_0/4]) + return 0; /* assume everything is ok */ + + for (i = PCI_BASE_ADDRESS_0/4; i < 64; ++i) { + if (radeon_cfg_after_resume[i] != rinfo->cfg_save[i]) + pci_write_config_dword(rinfo->pdev, i * 4, + rinfo->cfg_save[i]); + } + pci_write_config_word(rinfo->pdev, PCI_CACHE_LINE_SIZE, + rinfo->cfg_save[PCI_CACHE_LINE_SIZE/4]); + pci_write_config_word(rinfo->pdev, PCI_COMMAND, + rinfo->cfg_save[PCI_COMMAND/4]); + return 1; +} + + int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) { struct fb_info *info = pci_get_drvdata(pdev); struct radeonfb_info *rinfo = info->par; + int i; if (mesg.event == pdev->dev.power.power_state.event) return 0; @@ -2627,11 +2674,6 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) pmac_suspend_agp_for_card(pdev); #endif /* CONFIG_PPC_PMAC */ - /* It's unclear whether or when the generic code will do that, so let's - * do it ourselves. We save state before we do any power management - */ - pci_save_state(pdev); - /* If we support wakeup from poweroff, we save all regs we can including cfg * space */ @@ -2656,6 +2698,9 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) mdelay(20); OUTREG(LVDS_GEN_CNTL, INREG(LVDS_GEN_CNTL) & ~(LVDS_DIGON)); } + // FIXME: Use PCI layer + for (i = 0; i < 64; ++i) + pci_read_config_dword(pdev, i * 4, &rinfo->cfg_save[i]); pci_disable_device(pdev); } /* If we support D2, we go to it (should be fixed later with a flag forcing @@ -2672,13 +2717,6 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg) return 0; } -static int radeon_check_power_loss(struct radeonfb_info *rinfo) -{ - return rinfo->save_regs[4] != INPLL(CLK_PIN_CNTL) || - rinfo->save_regs[2] != INPLL(MCLK_CNTL) || - rinfo->save_regs[3] != INPLL(SCLK_CNTL); -} - int radeonfb_pci_resume(struct pci_dev *pdev) { struct fb_info *info = pci_get_drvdata(pdev); @@ -2697,13 +2735,20 @@ int radeonfb_pci_resume(struct pci_dev *pdev) printk(KERN_DEBUG "radeonfb (%s): resuming from state: %d...\n", pci_name(pdev), pdev->dev.power.power_state.event); - /* PCI state will have been restored by the core, so - * we should be in D0 now with our config space fully - * restored - */ + + if (pci_enable_device(pdev)) { + rc = -ENODEV; + printk(KERN_ERR "radeonfb (%s): can't enable PCI device !\n", + pci_name(pdev)); + goto bail; + } + pci_set_master(pdev); + if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) { - /* Wakeup chip */ - if ((rinfo->pm_mode & radeon_pm_off) && radeon_check_power_loss(rinfo)) { + /* Wakeup chip. Check from config space if we were powered off + * (todo: additionally, check CLK_PIN_CNTL too) + */ + if ((rinfo->pm_mode & radeon_pm_off) && radeon_restore_pci_cfg(rinfo)) { if (rinfo->reinit_func != NULL) rinfo->reinit_func(rinfo); else { diff --git a/trunk/drivers/video/aty/radeonfb.h b/trunk/drivers/video/aty/radeonfb.h index 7351e66c7f54..3ea1b00fdd22 100644 --- a/trunk/drivers/video/aty/radeonfb.h +++ b/trunk/drivers/video/aty/radeonfb.h @@ -361,6 +361,8 @@ struct radeonfb_info { #ifdef CONFIG_FB_RADEON_I2C struct radeon_i2c_chan i2c[4]; #endif + + u32 cfg_save[64]; }; diff --git a/trunk/kernel/async.c b/trunk/kernel/async.c index 67a2be71f517..0c90d500ab68 100644 --- a/trunk/kernel/async.c +++ b/trunk/kernel/async.c @@ -133,7 +133,7 @@ static void run_one_entry(void) /* 2) move it to the running queue */ list_del(&entry->list); - list_add_tail(&entry->list, &async_running); + list_add_tail(&entry->list, entry->running); spin_unlock_irqrestore(&async_lock, flags); /* 3) run it (and print duration)*/ @@ -210,7 +210,7 @@ static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct l async_cookie_t async_schedule(async_func_ptr *ptr, void *data) { - return __async_schedule(ptr, data, &async_pending); + return __async_schedule(ptr, data, &async_running); } EXPORT_SYMBOL_GPL(async_schedule);