drm/vgaarb: add VGA arbitration support to the drm and kms.
authorDave Airlie <airlied@redhat.com>
Mon, 21 Sep 2009 04:33:58 +0000 (14:33 +1000)
committerDave Airlie <airlied@redhat.com>
Mon, 21 Sep 2009 05:00:27 +0000 (15:00 +1000)
VGA arb requires DRM support for non-kms drivers, to turn on/off
irqs when disabling the mem/io regions.

VGA arb requires KMS support for GPUs where we can turn off VGA
decoding. Currently we know how to do this for intel and radeon
kms drivers, which allows them to be removed from the arbiter.

This patch comes from Fedora rawhide kernel.

Signed-off-by: Dave Airlie <airlied@redhat.com>
13 files changed:
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_device.c
include/drm/drmP.h

index f85aaf21e7839b65f821d903a556ef38661cc6e8..0a6f0b3bdc787eae8c29f54086dcb089f586b5c9 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <linux/interrupt.h>   /* For task queue support */
 
+#include <linux/vgaarb.h>
 /**
  * Get interrupt from bus id.
  *
@@ -171,6 +172,26 @@ err:
 }
 EXPORT_SYMBOL(drm_vblank_init);
 
+static void drm_irq_vgaarb_nokms(void *cookie, bool state)
+{
+       struct drm_device *dev = cookie;
+
+       if (dev->driver->vgaarb_irq) {
+               dev->driver->vgaarb_irq(dev, state);
+               return;
+       }
+
+       if (!dev->irq_enabled)
+               return;
+
+       if (state)
+               dev->driver->irq_uninstall(dev);
+       else {
+               dev->driver->irq_preinstall(dev);
+               dev->driver->irq_postinstall(dev);
+       }
+}
+
 /**
  * Install IRQ handler.
  *
@@ -231,6 +252,9 @@ int drm_irq_install(struct drm_device *dev)
                return ret;
        }
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               vga_client_register(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms, NULL);
+
        /* After installing handler */
        ret = dev->driver->irq_postinstall(dev);
        if (ret < 0) {
@@ -279,6 +303,9 @@ int drm_irq_uninstall(struct drm_device * dev)
 
        DRM_DEBUG("irq=%d\n", dev->pdev->irq);
 
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               vga_client_register(dev->pdev, NULL, NULL, NULL);
+
        dev->driver->irq_uninstall(dev);
 
        free_irq(dev->pdev->irq, dev);
index 9909505d070a237026774a54d614a102d17c82bb..5a49a1867b357841d24342859db0b79fab3a982d 100644 (file)
@@ -33,6 +33,7 @@
 #include "intel_drv.h"
 #include "i915_drm.h"
 #include "i915_drv.h"
+#include <linux/vgaarb.h>
 
 /* Really want an OS-independent resettable timer.  Would like to have
  * this loop run for (eg) 3 sec, but have the timer reset every time
@@ -1012,6 +1013,19 @@ static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
        return 0;
 }
 
+/* true = enable decode, false = disable decoder */
+static unsigned int i915_vga_set_decode(void *cookie, bool state)
+{
+       struct drm_device *dev = cookie;
+
+       intel_modeset_vga_set_state(dev, state);
+       if (state)
+               return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
+                      VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+       else
+               return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+}
+
 static int i915_load_modeset_init(struct drm_device *dev,
                                  unsigned long prealloc_size,
                                  unsigned long agp_size)
@@ -1057,6 +1071,11 @@ static int i915_load_modeset_init(struct drm_device *dev,
        if (ret)
                DRM_INFO("failed to find VBIOS tables\n");
 
+       /* if we have > 1 VGA cards, then disable the radeon VGA resources */
+       ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
+       if (ret)
+               goto destroy_ringbuffer;
+
        ret = drm_irq_install(dev);
        if (ret)
                goto destroy_ringbuffer;
@@ -1324,6 +1343,7 @@ int i915_driver_unload(struct drm_device *dev)
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                drm_irq_uninstall(dev);
+               vga_client_register(dev->pdev, NULL, NULL, NULL);
        }
 
        if (dev->pdev->msi_enabled)
index 77ed060b4292d5f583224405871a6c81b00a3867..a0632f8e76ace4735247ff0b91c82c180719aac8 100644 (file)
@@ -766,6 +766,7 @@ static inline void opregion_enable_asle(struct drm_device *dev) { return; }
 /* modesetting */
 extern void intel_modeset_init(struct drm_device *dev);
 extern void intel_modeset_cleanup(struct drm_device *dev);
+extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
 
 /**
  * Lock test for when it's just for synchronization of ring access.
index e38cd21161c8f21f8f0f4650d1ce68f3d5276b12..3f796355346403f4cd868534b39b29866d3bd508 100644 (file)
@@ -30,6 +30,7 @@
  * fb aperture size and the amount of pre-reserved memory.
  */
 #define INTEL_GMCH_CTRL                0x52
+#define INTEL_GMCH_VGA_DISABLE  (1 << 1)
 #define INTEL_GMCH_ENABLED     0x4
 #define INTEL_GMCH_MEM_MASK    0x1
 #define INTEL_GMCH_MEM_64M     0x1
index 155719ff99d148d06ca93a9720e6e15c830e259e..0227b1652906cc0ad345863f2ead6c8bce6025dc 100644 (file)
@@ -3917,3 +3917,20 @@ struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
 
        return &intel_output->enc;
 }
+
+/*
+ * set vga decode state - true == enable VGA decode
+ */
+int intel_modeset_vga_set_state(struct drm_device *dev, bool state)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u16 gmch_ctrl;
+
+       pci_read_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, &gmch_ctrl);
+       if (state)
+               gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE;
+       else
+               gmch_ctrl |= INTEL_GMCH_VGA_DISABLE;
+       pci_write_config_word(dev_priv->bridge_dev, INTEL_GMCH_CTRL, gmch_ctrl);
+       return 0;
+}
index b9e47f1e1cc010a228c1537d4d1e165344cc09f4..3a0004f755d047269a47feef407d970d63d235f5 100644 (file)
@@ -178,4 +178,5 @@ extern int intel_framebuffer_create(struct drm_device *dev,
                                    struct drm_mode_fb_cmd *mode_cmd,
                                    struct drm_framebuffer **fb,
                                    struct drm_gem_object *obj);
+
 #endif /* __INTEL_DRV_H__ */
index 737970b43aef817d5dafd392c9685aa76d50ea65..be51c5f7d0f659f9baa1efaae4dfe662c498d6e5 100644 (file)
@@ -1955,6 +1955,20 @@ void r100_vram_init_sizes(struct radeon_device *rdev)
                rdev->mc.real_vram_size = rdev->mc.aper_size;
 }
 
+void r100_vga_set_state(struct radeon_device *rdev, bool state)
+{
+       uint32_t temp;
+
+       temp = RREG32(RADEON_CONFIG_CNTL);
+       if (state == false) {
+               temp &= ~(1<<8);
+               temp |= (1<<9);
+       } else {
+               temp &= ~(1<<9);
+       }
+       WREG32(RADEON_CONFIG_CNTL, temp);
+}
+
 void r100_vram_info(struct radeon_device *rdev)
 {
        r100_vram_get_type(rdev);
index 5f42fad19190b7bf45af6b6082fe9ceaa3fe0b7d..eab31c1d6df1612c4b91a80f4eb3de876e803c6d 100644 (file)
@@ -1499,6 +1499,20 @@ int r600_startup(struct radeon_device *rdev)
        return 0;
 }
 
+void r600_vga_set_state(struct radeon_device *rdev, bool state)
+{
+       uint32_t temp;
+
+       temp = RREG32(CONFIG_CNTL);
+       if (state == false) {
+               temp &= ~(1<<0);
+               temp |= (1<<1);
+       } else {
+               temp &= ~(1<<1);
+       }
+       WREG32(CONFIG_CNTL, temp);
+}
+
 int r600_resume(struct radeon_device *rdev)
 {
        int r;
index 723295f59281f2dd61d8b0be13a5def2db71af20..4a9028a85c9b225ce4cda0ccf8e82a77fa03fa26 100644 (file)
@@ -78,6 +78,7 @@
 #define CB_COLOR0_MASK                                  0x28100
 
 #define        CONFIG_MEMSIZE                                  0x5428
+#define CONFIG_CNTL                                    0x5424
 #define        CP_STAT                                         0x8680
 #define        CP_COHER_BASE                                   0x85F8
 #define        CP_DEBUG                                        0xC1FC
index 817af8ecff10f00646531a4931ac3100097a074d..c839b608970fb4d2bc2d845c4b57a47d3a20ad61 100644 (file)
@@ -596,6 +596,7 @@ struct radeon_asic {
        int (*suspend)(struct radeon_device *rdev);
        void (*errata)(struct radeon_device *rdev);
        void (*vram_info)(struct radeon_device *rdev);
+       void (*vga_set_state)(struct radeon_device *rdev, bool state);
        int (*gpu_reset)(struct radeon_device *rdev);
        int (*mc_init)(struct radeon_device *rdev);
        void (*mc_fini)(struct radeon_device *rdev);
@@ -954,6 +955,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
 #define radeon_cs_parse(p) rdev->asic->cs_parse((p))
 #define radeon_errata(rdev) (rdev)->asic->errata((rdev))
 #define radeon_vram_info(rdev) (rdev)->asic->vram_info((rdev))
+#define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state))
 #define radeon_gpu_reset(rdev) (rdev)->asic->gpu_reset((rdev))
 #define radeon_mc_init(rdev) (rdev)->asic->mc_init((rdev))
 #define radeon_mc_fini(rdev) (rdev)->asic->mc_fini((rdev))
index 5f2a9e6f12c5baeaa36bf2e7e8bc34afcb220a0a..8968f78fa1e30e8424b101a8ccf477d4885286d5 100644 (file)
@@ -47,6 +47,7 @@ uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg);
 void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 void r100_errata(struct radeon_device *rdev);
 void r100_vram_info(struct radeon_device *rdev);
+void r100_vga_set_state(struct radeon_device *rdev, bool state);
 int r100_gpu_reset(struct radeon_device *rdev);
 int r100_mc_init(struct radeon_device *rdev);
 void r100_mc_fini(struct radeon_device *rdev);
@@ -89,6 +90,7 @@ static struct radeon_asic r100_asic = {
        .init = &r100_init,
        .errata = &r100_errata,
        .vram_info = &r100_vram_info,
+       .vga_set_state = &r100_vga_set_state,
        .gpu_reset = &r100_gpu_reset,
        .mc_init = &r100_mc_init,
        .mc_fini = &r100_mc_fini,
@@ -158,6 +160,7 @@ static struct radeon_asic r300_asic = {
        .init = &r300_init,
        .errata = &r300_errata,
        .vram_info = &r300_vram_info,
+       .vga_set_state = &r100_vga_set_state,
        .gpu_reset = &r300_gpu_reset,
        .mc_init = &r300_mc_init,
        .mc_fini = &r300_mc_fini,
@@ -208,6 +211,7 @@ static struct radeon_asic r420_asic = {
        .resume = &r420_resume,
        .errata = NULL,
        .vram_info = NULL,
+       .vga_set_state = &r100_vga_set_state,
        .gpu_reset = &r300_gpu_reset,
        .mc_init = NULL,
        .mc_fini = NULL,
@@ -262,6 +266,7 @@ static struct radeon_asic rs400_asic = {
        .init = &r300_init,
        .errata = &rs400_errata,
        .vram_info = &rs400_vram_info,
+       .vga_set_state = &r100_vga_set_state,
        .gpu_reset = &r300_gpu_reset,
        .mc_init = &rs400_mc_init,
        .mc_fini = &rs400_mc_fini,
@@ -323,6 +328,7 @@ static struct radeon_asic rs600_asic = {
        .init = &rs600_init,
        .errata = &rs600_errata,
        .vram_info = &rs600_vram_info,
+       .vga_set_state = &r100_vga_set_state,
        .gpu_reset = &r300_gpu_reset,
        .mc_init = &rs600_mc_init,
        .mc_fini = &rs600_mc_fini,
@@ -372,6 +378,7 @@ static struct radeon_asic rs690_asic = {
        .init = &rs600_init,
        .errata = &rs690_errata,
        .vram_info = &rs690_vram_info,
+       .vga_set_state = &r100_vga_set_state,
        .gpu_reset = &r300_gpu_reset,
        .mc_init = &rs690_mc_init,
        .mc_fini = &rs690_mc_fini,
@@ -428,6 +435,7 @@ static struct radeon_asic rv515_asic = {
        .init = &rv515_init,
        .errata = &rv515_errata,
        .vram_info = &rv515_vram_info,
+       .vga_set_state = &r100_vga_set_state,
        .gpu_reset = &rv515_gpu_reset,
        .mc_init = &rv515_mc_init,
        .mc_fini = &rv515_mc_fini,
@@ -477,6 +485,7 @@ static struct radeon_asic r520_asic = {
        .init = &rv515_init,
        .errata = &r520_errata,
        .vram_info = &r520_vram_info,
+       .vga_set_state = &r100_vga_set_state,
        .gpu_reset = &rv515_gpu_reset,
        .mc_init = &r520_mc_init,
        .mc_fini = &r520_mc_fini,
@@ -520,6 +529,7 @@ int r600_init(struct radeon_device *rdev);
 void r600_fini(struct radeon_device *rdev);
 int r600_suspend(struct radeon_device *rdev);
 int r600_resume(struct radeon_device *rdev);
+void r600_vga_set_state(struct radeon_device *rdev, bool state);
 int r600_wb_init(struct radeon_device *rdev);
 void r600_wb_fini(struct radeon_device *rdev);
 void r600_cp_commit(struct radeon_device *rdev);
@@ -556,6 +566,7 @@ static struct radeon_asic r600_asic = {
        .resume = &r600_resume,
        .cp_commit = &r600_cp_commit,
        .vram_info = NULL,
+       .vga_set_state = &r600_vga_set_state,
        .gpu_reset = &r600_gpu_reset,
        .mc_init = NULL,
        .mc_fini = NULL,
@@ -606,6 +617,7 @@ static struct radeon_asic rv770_asic = {
        .cp_commit = &r600_cp_commit,
        .vram_info = NULL,
        .gpu_reset = &rv770_gpu_reset,
+       .vga_set_state = &r600_vga_set_state,
        .mc_init = NULL,
        .mc_fini = NULL,
        .wb_init = &r600_wb_init,
index 8a40c616b534894e5aff553bca13e6f4070348ff..daf5db780956c2bc7738912a48f5407e1d1182ca 100644 (file)
@@ -29,6 +29,7 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/radeon_drm.h>
+#include <linux/vgaarb.h>
 #include "radeon_reg.h"
 #include "radeon.h"
 #include "radeon_asic.h"
@@ -480,7 +481,18 @@ void radeon_combios_fini(struct radeon_device *rdev)
 {
 }
 
+/* if we get transitioned to only one device, tak VGA back */
+static unsigned int radeon_vga_set_decode(void *cookie, bool state)
+{
+       struct radeon_device *rdev = cookie;
 
+       radeon_vga_set_state(rdev, state);
+       if (state)
+               return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
+                      VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+       else
+               return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+}
 /*
  * Radeon device.
  */
@@ -578,6 +590,13 @@ int radeon_device_init(struct radeon_device *rdev,
        if (r) {
                return r;
        }
+
+       /* if we have > 1 VGA cards, then disable the radeon VGA resources */
+       r = vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode);
+       if (r) {
+               return -EINVAL;
+       }
+
        if (!rdev->new_init_path) {
                /* Setup errata flags */
                radeon_errata(rdev);
@@ -586,7 +605,6 @@ int radeon_device_init(struct radeon_device *rdev,
                /* Initialize surface registers */
                radeon_surface_init(rdev);
 
-               /* TODO: disable VGA need to use VGA request */
                /* BIOS*/
                if (!radeon_get_bios(rdev)) {
                        if (ASIC_IS_AVIVO(rdev))
@@ -697,6 +715,7 @@ void radeon_device_fini(struct radeon_device *rdev)
                radeon_agp_fini(rdev);
 #endif
                radeon_irq_kms_fini(rdev);
+               vga_client_register(rdev->pdev, NULL, NULL, NULL);
                radeon_fence_driver_fini(rdev);
                radeon_clocks_fini(rdev);
                radeon_object_fini(rdev);
index eeefb6369e19d519ff6a408a5208935745c3632a..c8e64bbadbcf3c99ccc4eba20a3e13610779a9a9 100644 (file)
@@ -810,6 +810,9 @@ struct drm_driver {
        int (*gem_init_object) (struct drm_gem_object *obj);
        void (*gem_free_object) (struct drm_gem_object *obj);
 
+       /* vga arb irq handler */
+       void (*vgaarb_irq)(struct drm_device *dev, bool state);
+
        /* Driver private ops for this object */
        struct vm_operations_struct *gem_vm_ops;