]> git.itanic.dy.fi Git - linux-stable/commitdiff
drm/gma500: Fix (vblank) IRQs not working after suspend/resume
authorHans de Goede <hdegoede@redhat.com>
Tue, 6 Sep 2022 20:38:52 +0000 (22:38 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 28 Sep 2022 09:32:23 +0000 (11:32 +0200)
[ Upstream commit 235fdbc32d559db21e580f85035c59372704f09e ]

Fix gnome-shell (and other page-flip users) hanging after suspend/resume
because of the gma500's IRQs not working.

This fixes 2 problems with the IRQ handling:

1. gma_power_off() calls gma_irq_uninstall() which does a free_irq(), but
   gma_power_on() called gma_irq_preinstall() + gma_irq_postinstall() which
   do not call request_irq. Replace the pre- + post-install calls with
   gma_irq_install() which does prep + request + post.

2. After fixing 1. IRQs still do not work on a Packard Bell Dot SC (Intel
   Atom N2600, cedarview) netbook.

   Cederview uses MSI interrupts and it seems that the BIOS re-configures
   things back to normal APIC based interrupts during S3 suspend. There is
   some MSI PCI-config registers save/restore code which tries to deal with
   this, but on the Packard Bell Dot SC this is not sufficient to restore
   MSI IRQ functionality after a suspend/resume.

   Replace the PCI-config registers save/restore with pci_disable_msi() on
   suspend + pci_enable_msi() on resume. Fixing e.g. gnome-shell hanging.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220906203852.527663-4-hdegoede@redhat.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/gma500/cdv_device.c
drivers/gpu/drm/gma500/oaktrail_device.c
drivers/gpu/drm/gma500/power.c
drivers/gpu/drm/gma500/psb_drv.c
drivers/gpu/drm/gma500/psb_drv.h
drivers/gpu/drm/gma500/psb_irq.c
drivers/gpu/drm/gma500/psb_irq.h

index dd32b484dd82557b77a918c99c0953f78f4fb1e7..ce96234f3df2084f80702f060926d77d3b981068 100644 (file)
@@ -581,11 +581,9 @@ static const struct psb_offset cdv_regmap[2] = {
 static int cdv_chip_setup(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
 static int cdv_chip_setup(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
-       struct pci_dev *pdev = to_pci_dev(dev->dev);
        INIT_WORK(&dev_priv->hotplug_work, cdv_hotplug_work_func);
 
        INIT_WORK(&dev_priv->hotplug_work, cdv_hotplug_work_func);
 
-       if (pci_enable_msi(pdev))
-               dev_warn(dev->dev, "Enabling MSI failed!\n");
+       dev_priv->use_msi = true;
        dev_priv->regmap = cdv_regmap;
        gma_get_core_freq(dev);
        psb_intel_opregion_init(dev);
        dev_priv->regmap = cdv_regmap;
        gma_get_core_freq(dev);
        psb_intel_opregion_init(dev);
index 5923a9c8931224565545fc163b7602105546a072..f90e628cb482c097f503fc82701e4084a2b00d4d 100644 (file)
@@ -501,12 +501,9 @@ static const struct psb_offset oaktrail_regmap[2] = {
 static int oaktrail_chip_setup(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
 static int oaktrail_chip_setup(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
-       struct pci_dev *pdev = to_pci_dev(dev->dev);
        int ret;
 
        int ret;
 
-       if (pci_enable_msi(pdev))
-               dev_warn(dev->dev, "Enabling MSI failed!\n");
-
+       dev_priv->use_msi = true;
        dev_priv->regmap = oaktrail_regmap;
 
        ret = mid_chip_setup(dev);
        dev_priv->regmap = oaktrail_regmap;
 
        ret = mid_chip_setup(dev);
index b91de6d36e412e2b4dbbd3f179fd695781f119a3..66873085d45059797cdc94d8ab37ba5513bdd70c 100644 (file)
@@ -139,8 +139,6 @@ static void gma_suspend_pci(struct pci_dev *pdev)
        dev_priv->regs.saveBSM = bsm;
        pci_read_config_dword(pdev, 0xFC, &vbt);
        dev_priv->regs.saveVBT = vbt;
        dev_priv->regs.saveBSM = bsm;
        pci_read_config_dword(pdev, 0xFC, &vbt);
        dev_priv->regs.saveVBT = vbt;
-       pci_read_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, &dev_priv->msi_addr);
-       pci_read_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, &dev_priv->msi_data);
 
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
 
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
@@ -168,9 +166,6 @@ static bool gma_resume_pci(struct pci_dev *pdev)
        pci_restore_state(pdev);
        pci_write_config_dword(pdev, 0x5c, dev_priv->regs.saveBSM);
        pci_write_config_dword(pdev, 0xFC, dev_priv->regs.saveVBT);
        pci_restore_state(pdev);
        pci_write_config_dword(pdev, 0x5c, dev_priv->regs.saveBSM);
        pci_write_config_dword(pdev, 0xFC, dev_priv->regs.saveVBT);
-       /* restoring MSI address and data in PCIx space */
-       pci_write_config_dword(pdev, PSB_PCIx_MSI_ADDR_LOC, dev_priv->msi_addr);
-       pci_write_config_dword(pdev, PSB_PCIx_MSI_DATA_LOC, dev_priv->msi_data);
        ret = pci_enable_device(pdev);
 
        if (ret != 0)
        ret = pci_enable_device(pdev);
 
        if (ret != 0)
@@ -223,8 +218,7 @@ int gma_power_resume(struct device *_dev)
        mutex_lock(&power_mutex);
        gma_resume_pci(pdev);
        gma_resume_display(pdev);
        mutex_lock(&power_mutex);
        gma_resume_pci(pdev);
        gma_resume_display(pdev);
-       gma_irq_preinstall(dev);
-       gma_irq_postinstall(dev);
+       gma_irq_install(dev);
        mutex_unlock(&power_mutex);
        return 0;
 }
        mutex_unlock(&power_mutex);
        return 0;
 }
index 1d8744f3e7020760d4beffba2429815a58f93035..54e756b486060b5388680a93075dfcbd6054ab44 100644 (file)
@@ -383,7 +383,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long flags)
        PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R);
        spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
 
        PSB_WVDC32(0xFFFFFFFF, PSB_INT_MASK_R);
        spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
 
-       gma_irq_install(dev, pdev->irq);
+       gma_irq_install(dev);
 
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
 
 
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
 
index 0ddfec1a0851d5a233d8ed2d18e78ce05411bd0b..4c3fc5eaf6ad5d446abcfbb5f1c885c15421b213 100644 (file)
@@ -490,6 +490,7 @@ struct drm_psb_private {
        int rpm_enabled;
 
        /* MID specific */
        int rpm_enabled;
 
        /* MID specific */
+       bool use_msi;
        bool has_gct;
        struct oaktrail_gct_data gct_data;
 
        bool has_gct;
        struct oaktrail_gct_data gct_data;
 
@@ -499,10 +500,6 @@ struct drm_psb_private {
        /* Register state */
        struct psb_save_area regs;
 
        /* Register state */
        struct psb_save_area regs;
 
-       /* MSI reg save */
-       uint32_t msi_addr;
-       uint32_t msi_data;
-
        /* Hotplug handling */
        struct work_struct hotplug_work;
 
        /* Hotplug handling */
        struct work_struct hotplug_work;
 
index e6e6d61bbeab646d05026564d51d9b53174d44f5..038f18ed0a95ee3b43759e32d3c1d84730111dfe 100644 (file)
@@ -316,17 +316,24 @@ void gma_irq_postinstall(struct drm_device *dev)
        spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
 }
 
        spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
 }
 
-int gma_irq_install(struct drm_device *dev, unsigned int irq)
+int gma_irq_install(struct drm_device *dev)
 {
 {
+       struct drm_psb_private *dev_priv = to_drm_psb_private(dev);
+       struct pci_dev *pdev = to_pci_dev(dev->dev);
        int ret;
 
        int ret;
 
-       if (irq == IRQ_NOTCONNECTED)
+       if (dev_priv->use_msi && pci_enable_msi(pdev)) {
+               dev_warn(dev->dev, "Enabling MSI failed!\n");
+               dev_priv->use_msi = false;
+       }
+
+       if (pdev->irq == IRQ_NOTCONNECTED)
                return -ENOTCONN;
 
        gma_irq_preinstall(dev);
 
        /* PCI devices require shared interrupts. */
                return -ENOTCONN;
 
        gma_irq_preinstall(dev);
 
        /* PCI devices require shared interrupts. */
-       ret = request_irq(irq, gma_irq_handler, IRQF_SHARED, dev->driver->name, dev);
+       ret = request_irq(pdev->irq, gma_irq_handler, IRQF_SHARED, dev->driver->name, dev);
        if (ret)
                return ret;
 
        if (ret)
                return ret;
 
@@ -369,6 +376,8 @@ void gma_irq_uninstall(struct drm_device *dev)
        spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
 
        free_irq(pdev->irq, dev);
        spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
 
        free_irq(pdev->irq, dev);
+       if (dev_priv->use_msi)
+               pci_disable_msi(pdev);
 }
 
 int gma_crtc_enable_vblank(struct drm_crtc *crtc)
 }
 
 int gma_crtc_enable_vblank(struct drm_crtc *crtc)
index b51e395194fff2c50fd46cb369377f0007ce09ec..7648f69824a5d4c5b2edf381b30c56524c4cf9c6 100644 (file)
@@ -17,7 +17,7 @@ struct drm_device;
 
 void gma_irq_preinstall(struct drm_device *dev);
 void gma_irq_postinstall(struct drm_device *dev);
 
 void gma_irq_preinstall(struct drm_device *dev);
 void gma_irq_postinstall(struct drm_device *dev);
-int  gma_irq_install(struct drm_device *dev, unsigned int irq);
+int  gma_irq_install(struct drm_device *dev);
 void gma_irq_uninstall(struct drm_device *dev);
 
 int  gma_crtc_enable_vblank(struct drm_crtc *crtc);
 void gma_irq_uninstall(struct drm_device *dev);
 
 int  gma_crtc_enable_vblank(struct drm_crtc *crtc);