Commit 235fdbc3 authored by Hans de Goede's avatar Hans de Goede Committed by Patrik Jakobsson
Browse files

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: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarPatrik Jakobsson <patrik.r.jakobsson@gmail.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220906203852.527663-4-hdegoede@redhat.com
parent b6f25c3b
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -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);
+1 −4
Original line number Diff line number Diff line
@@ -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);
+1 −7
Original line number Diff line number Diff line
@@ -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;
}
+1 −1
Original line number Diff line number Diff line
@@ -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 */

+1 −4
Original line number Diff line number Diff line
@@ -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;

Loading