drm/gma500: Fix (vblank) IRQs not working after suspend/resume
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
This commit is contained in:
Родитель
b6f25c3b94
Коммит
235fdbc32d
|
@ -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);
|
||||
struct pci_dev *pdev = to_pci_dev(dev->dev);
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
struct pci_dev *pdev = to_pci_dev(dev->dev);
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
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);
|
||||
|
@ -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);
|
||||
/* 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)
|
||||
|
@ -223,8 +218,7 @@ int gma_power_resume(struct device *_dev)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
gma_irq_install(dev, pdev->irq);
|
||||
gma_irq_install(dev);
|
||||
|
||||
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
|
||||
|
||||
|
|
|
@ -490,6 +490,7 @@ struct drm_psb_private {
|
|||
int rpm_enabled;
|
||||
|
||||
/* MID specific */
|
||||
bool use_msi;
|
||||
bool has_gct;
|
||||
struct oaktrail_gct_data gct_data;
|
||||
|
||||
|
@ -499,10 +500,6 @@ struct drm_psb_private {
|
|||
/* 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;
|
||||
|
||||
|
|
|
@ -316,17 +316,24 @@ void gma_irq_postinstall(struct drm_device *dev)
|
|||
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;
|
||||
|
||||
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. */
|
||||
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;
|
||||
|
||||
|
@ -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);
|
||||
if (dev_priv->use_msi)
|
||||
pci_disable_msi(pdev);
|
||||
}
|
||||
|
||||
int gma_crtc_enable_vblank(struct drm_crtc *crtc)
|
||||
|
|
|
@ -17,7 +17,7 @@ struct drm_device;
|
|||
|
||||
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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче