rpms/kernel/devel drm-vga-arb.patch, 1.1, 1.2 kernel.spec, 1.1658, 1.1659 linux-2.6-vga-arb.patch, 1.1, 1.2
Dave Airlie
airlied at fedoraproject.org
Mon Jul 27 03:04:08 UTC 2009
Author: airlied
Update of /cvs/pkgs/rpms/kernel/devel
In directory cvs1.fedora.phx.redhat.com:/tmp/cvs-serv13546
Modified Files:
drm-vga-arb.patch kernel.spec linux-2.6-vga-arb.patch
Log Message:
* Mon Jul 27 2009 Dave Airlie <airlied at redhat.com>
- update vga arb code
drm-vga-arb.patch:
drivers/gpu/drm/drm_irq.c | 27 +++++++++++++++++++++++++++
drivers/gpu/drm/i915/i915_dma.c | 25 +++++++++++++++++++++++++
drivers/gpu/drm/i915/i915_drv.h | 1 +
drivers/gpu/drm/i915/i915_reg.h | 1 +
drivers/gpu/drm/i915/intel_display.c | 23 +++++++++++++++++++++++
drivers/gpu/drm/i915/intel_drv.h | 1 +
drivers/gpu/drm/radeon/r100.c | 14 ++++++++++++++
drivers/gpu/drm/radeon/radeon.h | 2 ++
drivers/gpu/drm/radeon/radeon_asic.h | 9 +++++++++
drivers/gpu/drm/radeon/radeon_device.c | 24 +++++++++++++++++++++++-
include/drm/drmP.h | 4 +++-
11 files changed, 129 insertions(+), 2 deletions(-)
Index: drm-vga-arb.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/drm-vga-arb.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -p -r1.1 -r1.2
--- drm-vga-arb.patch 16 Jul 2009 05:32:39 -0000 1.1
+++ drm-vga-arb.patch 27 Jul 2009 03:04:07 -0000 1.2
@@ -1,4 +1,4 @@
-From fb6efadf2336b3f194f5fc1733116d8965b0d88c Mon Sep 17 00:00:00 2001
+From c45aab9228c3a2e349bf6d1f3fa2575102fc8240 Mon Sep 17 00:00:00 2001
From: Dave Airlie <airlied at redhat.com>
Date: Thu, 16 Jul 2009 14:33:58 +1000
Subject: [PATCH] drm: add support to drm for VGA arbitration.
@@ -13,20 +13,21 @@ intel/kms: add support to disable VGA de
Signed-off-by: Dave Airlie <airlied at redhat.com>
---
- drivers/gpu/drm/drm_irq.c | 24 ++++++++++++++++++++++++
- drivers/gpu/drm/i915/i915_dma.c | 6 ++++++
+ drivers/gpu/drm/drm_irq.c | 27 +++++++++++++++++++++++++++
+ drivers/gpu/drm/i915/i915_dma.c | 25 +++++++++++++++++++++++++
+ drivers/gpu/drm/i915/i915_drv.h | 1 +
drivers/gpu/drm/i915/i915_reg.h | 1 +
- drivers/gpu/drm/i915/intel_display.c | 17 +++++++++++++++++
+ drivers/gpu/drm/i915/intel_display.c | 23 +++++++++++++++++++++++
drivers/gpu/drm/i915/intel_drv.h | 1 +
- drivers/gpu/drm/radeon/r100.c | 9 +++++++++
+ drivers/gpu/drm/radeon/r100.c | 14 ++++++++++++++
drivers/gpu/drm/radeon/radeon.h | 2 ++
drivers/gpu/drm/radeon/radeon_asic.h | 9 +++++++++
- drivers/gpu/drm/radeon/radeon_device.c | 5 ++++-
+ drivers/gpu/drm/radeon/radeon_device.c | 24 +++++++++++++++++++++++-
include/drm/drmP.h | 3 +++
- 10 files changed, 76 insertions(+), 1 deletions(-)
+ 11 files changed, 129 insertions(+), 1 deletions(-)
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
-index b4a3dbc..436889e 100644
+index b4a3dbc..dffc73d 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -37,6 +37,7 @@
@@ -37,7 +38,7 @@ index b4a3dbc..436889e 100644
/**
* Get interrupt from bus id.
*
-@@ -171,6 +172,23 @@ err:
+@@ -171,6 +172,26 @@ err:
}
EXPORT_SYMBOL(drm_vblank_init);
@@ -50,6 +51,9 @@ index b4a3dbc..436889e 100644
+ return;
+ }
+
++ if (!dev->irq_enabled)
++ return;
++
+ if (state)
+ dev->driver->irq_uninstall(dev);
+ else {
@@ -61,28 +65,28 @@ index b4a3dbc..436889e 100644
/**
* Install IRQ handler.
*
-@@ -231,6 +249,9 @@ int drm_irq_install(struct drm_device *dev)
+@@ -231,6 +252,9 @@ int drm_irq_install(struct drm_device *dev)
return ret;
}
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
-+ vga_set_irq_callback(dev->pdev, (void *)dev, drm_irq_vgaarb_nokms);
++ 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 +300,9 @@ int drm_irq_uninstall(struct drm_device * dev)
+@@ -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_set_irq_callback(dev->pdev, NULL, NULL);
++ vga_client_register(dev->pdev, NULL, NULL, NULL);
+
dev->driver->irq_uninstall(dev);
free_irq(dev->pdev->irq, dev);
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
-index 8c47831..391e496 100644
+index 8c47831..2530fb0 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -33,6 +33,7 @@
@@ -93,18 +97,63 @@ index 8c47831..391e496 100644
#define I915_DRV "i915_drv"
/* Really want an OS-independent resettable timer. Would like to have
-@@ -1029,6 +1030,11 @@ static int i915_load_modeset_init(struct drm_device *dev,
+@@ -984,6 +985,21 @@ static int i915_probe_agp(struct drm_device *dev, uint32_t *aperture_size,
+ return 0;
+ }
+
++/* if we get transitioned to only one device, tak VGA back */
++static unsigned int i915_vga_count_notify(void *cookie, int new_count)
++{
++ struct drm_device *dev = cookie;
++
++ if (new_count == 1) {
++ intel_modeset_vga_set_state(dev, true);
++ return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
++ VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
++ } else {
++ intel_modeset_vga_set_state(dev, false);
++ 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)
+@@ -1029,6 +1045,14 @@ static int i915_load_modeset_init(struct drm_device *dev,
if (ret)
DRM_INFO("failed to find VBIOS tables\n");
-+ /* tell the VGA arbiter to set off */
-+ ret = intel_modeset_vga_disable(dev);
-+ if (ret == 0)
-+ vga_set_legacy_decoding(dev->pdev, VGA_RSRC_NONE);
++ /* if we have > 1 VGA cards, then disable the radeon VGA resources */
++ ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_count_notify);
++ if (ret > 1) {
++ /* false is turn off VGA decode */
++ intel_modeset_vga_set_state(dev, false);
++ vga_set_legacy_decoding(dev->pdev, VGA_RSRC_NORMAL_IO|VGA_RSRC_NORMAL_MEM);
++ }
+
ret = drm_irq_install(dev);
if (ret)
goto destroy_ringbuffer;
+@@ -1278,6 +1302,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)
+diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
+index d087528..61a54a1 100644
+--- a/drivers/gpu/drm/i915/i915_drv.h
++++ b/drivers/gpu/drm/i915/i915_drv.h
+@@ -747,6 +747,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.
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 6c08584..3e3145e 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
@@ -118,15 +167,18 @@ index 6c08584..3e3145e 100644
#define INTEL_GMCH_MEM_MASK 0x1
#define INTEL_GMCH_MEM_64M 0x1
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
-index 508838e..ad7ef01 100644
+index 508838e..5440f3c 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
-@@ -3188,3 +3188,20 @@ struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
+@@ -3188,3 +3188,26 @@ struct drm_encoder *intel_best_encoder(struct drm_connector *connector)
return &intel_output->enc;
}
+
-+int intel_modeset_vga_disable(struct drm_device *dev)
++/*
++ * set vga decode state - true == enable VGA decode
++ */
++int intel_modeset_vga_set_state(struct drm_device *dev, bool state)
+{
+ struct pci_dev *bridge_dev;
+ u16 gmch_ctrl;
@@ -138,34 +190,42 @@ index 508838e..ad7ef01 100644
+ }
+
+ pci_read_config_word(bridge_dev, INTEL_GMCH_CTRL, &gmch_ctrl);
-+ gmch_ctrl |= INTEL_GMCH_VGA_DISABLE;
++ if (state)
++ gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE;
++ else
++ gmch_ctrl |= INTEL_GMCH_VGA_DISABLE;
+ pci_write_config_word(bridge_dev, INTEL_GMCH_CTRL, gmch_ctrl);
+ return 0;
+}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
-index 004541c..ab5be5b 100644
+index 004541c..a715f80 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -154,4 +154,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);
-+extern int intel_modeset_vga_disable(struct drm_device *dev);
++
#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
-index c550932..1fa6723 100644
+index c550932..b091ba7 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
-@@ -1256,6 +1256,15 @@ static void r100_vram_get_type(struct radeon_device *rdev)
+@@ -1256,6 +1256,20 @@ static void r100_vram_get_type(struct radeon_device *rdev)
}
}
-+void r100_vga_disable(struct radeon_device *rdev)
++void r100_vga_set_state(struct radeon_device *rdev, bool state)
+{
+ uint32_t temp;
++
+ temp = RREG32(RADEON_CONFIG_CNTL);
-+ temp &= ~(1<<8);
-+ temp |= (1<<9);
++ if (state == false) {
++ temp &= ~(1<<8);
++ temp |= (1<<9);
++ } else {
++ temp &= ~(1<<9);
++ }
+ WREG32(RADEON_CONFIG_CNTL, temp);
+}
+
@@ -173,14 +233,14 @@ index c550932..1fa6723 100644
{
r100_vram_get_type(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
-index d61f2fc..583bfb2 100644
+index d61f2fc..655f6af 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -499,6 +499,7 @@ struct radeon_asic {
int (*init)(struct radeon_device *rdev);
void (*errata)(struct radeon_device *rdev);
void (*vram_info)(struct radeon_device *rdev);
-+ void (*vga_disable)(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);
@@ -188,19 +248,19 @@ index d61f2fc..583bfb2 100644
#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_disable(rdev) (rdev)->asic->vga_disable((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))
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
-index e2e5673..4586819 100644
+index e2e5673..59c505c 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -46,6 +46,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_disable(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);
@@ -208,7 +268,7 @@ index e2e5673..4586819 100644
.init = &r100_init,
.errata = &r100_errata,
.vram_info = &r100_vram_info,
-+ .vga_disable = &r100_vga_disable,
++ .vga_set_state = &r100_vga_set_state,
.gpu_reset = &r100_gpu_reset,
.mc_init = &r100_mc_init,
.mc_fini = &r100_mc_fini,
@@ -216,7 +276,7 @@ index e2e5673..4586819 100644
.init = &r300_init,
.errata = &r300_errata,
.vram_info = &r300_vram_info,
-+ .vga_disable = &r100_vga_disable,
++ .vga_set_state = &r100_vga_set_state,
.gpu_reset = &r300_gpu_reset,
.mc_init = &r300_mc_init,
.mc_fini = &r300_mc_fini,
@@ -224,7 +284,7 @@ index e2e5673..4586819 100644
.init = &r300_init,
.errata = &r420_errata,
.vram_info = &r420_vram_info,
-+ .vga_disable = &r100_vga_disable,
++ .vga_set_state = &r100_vga_set_state,
.gpu_reset = &r300_gpu_reset,
.mc_init = &r420_mc_init,
.mc_fini = &r420_mc_fini,
@@ -232,7 +292,7 @@ index e2e5673..4586819 100644
.init = &r300_init,
.errata = &rs400_errata,
.vram_info = &rs400_vram_info,
-+ .vga_disable = &r100_vga_disable,
++ .vga_set_state = &r100_vga_set_state,
.gpu_reset = &r300_gpu_reset,
.mc_init = &rs400_mc_init,
.mc_fini = &rs400_mc_fini,
@@ -240,7 +300,7 @@ index e2e5673..4586819 100644
.init = &r300_init,
.errata = &rs600_errata,
.vram_info = &rs600_vram_info,
-+ .vga_disable = &r100_vga_disable,
++ .vga_set_state = &r100_vga_set_state,
.gpu_reset = &r300_gpu_reset,
.mc_init = &rs600_mc_init,
.mc_fini = &rs600_mc_fini,
@@ -248,7 +308,7 @@ index e2e5673..4586819 100644
.init = &r300_init,
.errata = &rs690_errata,
.vram_info = &rs690_vram_info,
-+ .vga_disable = &r100_vga_disable,
++ .vga_set_state = &r100_vga_set_state,
.gpu_reset = &r300_gpu_reset,
.mc_init = &rs690_mc_init,
.mc_fini = &rs690_mc_fini,
@@ -256,7 +316,7 @@ index e2e5673..4586819 100644
.init = &rv515_init,
.errata = &rv515_errata,
.vram_info = &rv515_vram_info,
-+ .vga_disable = &r100_vga_disable,
++ .vga_set_state = &r100_vga_set_state,
.gpu_reset = &rv515_gpu_reset,
.mc_init = &rv515_mc_init,
.mc_fini = &rv515_mc_fini,
@@ -264,12 +324,12 @@ index e2e5673..4586819 100644
.init = &rv515_init,
.errata = &r520_errata,
.vram_info = &r520_vram_info,
-+ .vga_disable = &r100_vga_disable,
++ .vga_set_state = &r100_vga_set_state,
.gpu_reset = &rv515_gpu_reset,
.mc_init = &r520_mc_init,
.mc_fini = &r520_mc_fini,
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
-index f97563d..c02f655 100644
+index f97563d..b391d12 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -29,6 +29,7 @@
@@ -280,17 +340,51 @@ index f97563d..c02f655 100644
#include "radeon_reg.h"
#include "radeon.h"
#include "radeon_asic.h"
-@@ -516,7 +517,9 @@ int radeon_device_init(struct radeon_device *rdev,
+@@ -440,7 +441,20 @@ void radeon_combios_fini(struct radeon_device *rdev)
+ int radeon_modeset_init(struct radeon_device *rdev);
+ void radeon_modeset_fini(struct radeon_device *rdev);
+
++/* if we get transitioned to only one device, tak VGA back */
++static unsigned int radeon_vga_count_notify(void *cookie, int new_count)
++{
++ struct radeon_device *rdev = cookie;
+
++ if (new_count == 1) {
++ radeon_vga_set_state(rdev, true);
++ return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
++ VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
++ } else {
++ radeon_vga_set_state(rdev, false);
++ return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
++ }
++}
+ /*
+ * Radeon device.
+ */
+@@ -516,7 +530,14 @@ int radeon_device_init(struct radeon_device *rdev,
/* Initialize surface registers */
radeon_surface_init(rdev);
- /* TODO: disable VGA need to use VGA request */
-+ radeon_vga_disable(rdev);
-+ vga_set_legacy_decoding(rdev->pdev, VGA_RSRC_NONE);
++ /* if we have > 1 VGA cards, then disable the radeon VGA resources */
++ ret = vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_count_notify);
++ if (ret > 1) {
++ /* false is turn off VGA decode */
++ radeon_vga_set_state(rdev, false);
++ vga_set_legacy_decoding(rdev->pdev, VGA_RSRC_NORMAL_IO|VGA_RSRC_NORMAL_MEM);
++ }
+
/* BIOS*/
if (!radeon_get_bios(rdev)) {
if (ASIC_IS_AVIVO(rdev))
+@@ -652,6 +673,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);
+ if (rdev->is_atom_bios) {
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 45b67d9..95106c7 100644
--- a/include/drm/drmP.h
Index: kernel.spec
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/kernel.spec,v
retrieving revision 1.1658
retrieving revision 1.1659
diff -u -p -r1.1658 -r1.1659
--- kernel.spec 27 Jul 2009 02:22:56 -0000 1.1658
+++ kernel.spec 27 Jul 2009 03:04:07 -0000 1.1659
@@ -1260,8 +1260,8 @@ ApplyPatch drm-page-flip.patch
ApplyPatch drm-intel-pm.patch
# VGA arb + drm
-#ApplyPatch linux-2.6-vga-arb.patch
-#ApplyPatch drm-vga-arb.patch
+ApplyPatch linux-2.6-vga-arb.patch
+ApplyPatch drm-vga-arb.patch
# linux1394 git patches
#ApplyPatch linux-2.6-firewire-git-update.patch
@@ -1894,6 +1894,9 @@ fi
# and build.
%changelog
+* Mon Jul 27 2009 Dave Airlie <airlied at redhat.com>
+- update vga arb code
+
* Mon Jul 27 2009 Matthew Garrett <mjg at redhat.com>
- drm-intel-pm.patch - Add runtime PM for Intel graphics
linux-2.6-vga-arb.patch:
drivers/gpu/Makefile | 2
drivers/gpu/vga/Kconfig | 10
drivers/gpu/vga/Makefile | 1
drivers/gpu/vga/vgaarb.c | 1125 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/pci/pci.c | 44 +
drivers/video/Kconfig | 2
include/linux/pci.h | 2
include/linux/vgaarb.h | 199 ++++++++
8 files changed, 1383 insertions(+), 2 deletions(-)
Index: linux-2.6-vga-arb.patch
===================================================================
RCS file: /cvs/pkgs/rpms/kernel/devel/linux-2.6-vga-arb.patch,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -p -r1.1 -r1.2
--- linux-2.6-vga-arb.patch 16 Jul 2009 05:32:39 -0000 1.1
+++ linux-2.6-vga-arb.patch 27 Jul 2009 03:04:07 -0000 1.2
@@ -1,23 +1,23 @@
-From 5141835bff8148617b702d9390a594b90dbd6933 Mon Sep 17 00:00:00 2001
+From eba2469d77b9f7d42f08bbd094312678cedae237 Mon Sep 17 00:00:00 2001
From: Tiago Vignatti <tiago.vignatti at nokia.com>
Date: Tue, 14 Jul 2009 15:57:29 +0300
Subject: [PATCH] vga: implements VGA arbitration on Linux
-airlied changes since v1:
-moved to using pr_* instead of debug printks,
-add IRQ hook for GPU drivers to be called back for irq disable around mem/io disable
-remove module load/unload, vga arb is a subsystem really and shouldn't be
-removable from the kernel, allow it for CONFIG_EMBEDDED
+changes since last patch:
+fixup unlock userspace api so it can't go < 0
+add exports for vga put/get/tryget
Signed-off-by: Tiago Vignatti <tiago.vignatti at nokia.com>
---
drivers/gpu/Makefile | 2 +-
drivers/gpu/vga/Kconfig | 10 +
drivers/gpu/vga/Makefile | 1 +
- drivers/gpu/vga/vgaarb.c | 1116 ++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/gpu/vga/vgaarb.c | 1125 ++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/pci/pci.c | 44 ++
drivers/video/Kconfig | 2 +
- include/linux/vgaarb.h | 170 +++++++
- 6 files changed, 1300 insertions(+), 1 deletions(-)
+ include/linux/pci.h | 2 +
+ include/linux/vgaarb.h | 198 ++++++++
+ 8 files changed, 1383 insertions(+), 1 deletions(-)
create mode 100644 drivers/gpu/vga/Kconfig
create mode 100644 drivers/gpu/vga/Makefile
create mode 100644 drivers/gpu/vga/vgaarb.c
@@ -55,10 +55,10 @@ index 0000000..7cc8c1e
+obj-$(CONFIG_VGA_ARB) += vgaarb.o
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
new file mode 100644
-index 0000000..09cf259
+index 0000000..ab77d4b
--- /dev/null
+++ b/drivers/gpu/vga/vgaarb.c
-@@ -0,0 +1,1116 @@
+@@ -0,0 +1,1125 @@
+/*
+ * vgaarb.c
+ *
@@ -102,14 +102,54 @@ index 0000000..09cf259
+ unsigned int mem_norm_cnt; /* normal MEM count */
+
+ /* allow IRQ enable/disable hook */
-+ void *irq_cookie;
++ void *cookie;
+ void (*irq_set_state)(void *cookie, bool enable);
++ unsigned int (*count_notify)(void *cookie, int new_count);
+};
+
+static LIST_HEAD(vga_list);
++static int vga_count;
+static DEFINE_SPINLOCK(vga_lock);
+static DECLARE_WAIT_QUEUE_HEAD(vga_wait_queue);
+
++
++static const char *vga_iostate_to_str(unsigned int iostate)
++{
++ /* Ignore VGA_RSRC_IO and VGA_RSRC_MEM */
++ iostate &= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
++ switch (iostate) {
++ case VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM:
++ return "io+mem";
++ case VGA_RSRC_LEGACY_IO:
++ return "io";
++ case VGA_RSRC_LEGACY_MEM:
++ return "mem";
++ }
++ return "none";
++}
++
++static int vga_str_to_iostate(char *buf, int str_size, int *io_state)
++{
++ /* we could in theory hand out locks on IO and mem
++ * separately to userspace but it can cause deadlocks */
++ if (strncmp(buf, "none", 4) == 0) {
++ *io_state = VGA_RSRC_NONE;
++ return 1;
++ }
++
++ /* XXX We're not chekcing the str_size! */
++ if (strncmp(buf, "io+mem", 6) == 0)
++ goto both;
++ else if (strncmp(buf, "io", 2) == 0)
++ goto both;
++ else if (strncmp(buf, "mem", 3) == 0)
++ goto both;
++ return 0;
++both:
++ *io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
++ return 1;
++}
++
+#ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE
+/* this is only used a cookie - it should not be dereferenced */
+static struct pci_dev *vga_default;
@@ -123,8 +163,8 @@ index 0000000..09cf259
+ struct vga_device *vgadev;
+
+ list_for_each_entry(vgadev, &vga_list, list)
-+ if (pdev == vgadev->pdev)
-+ return vgadev;
++ if (pdev == vgadev->pdev)
++ return vgadev;
+ return NULL;
+}
+
@@ -139,98 +179,15 @@ index 0000000..09cf259
+static inline void vga_irq_set_state(struct vga_device *vgadev, bool state)
+{
+ if (vgadev->irq_set_state)
-+ vgadev->irq_set_state(vgadev->irq_cookie, state);
++ vgadev->irq_set_state(vgadev->cookie, state);
+}
-+/* Architecture can override enabling/disabling of a given
-+ * device resources here
-+ *
-+ * TODO: <benh> you can try to be "smart" and if for example you have 2 cards
-+ * that are behind separate bridges, you need only swapping the bridge controls
-+ * and you can keep the card master IO and memory enable.
-+ */
-+#ifndef __ARCH_HAS_VGA_DISABLE_RESOURCES
-+static inline void vga_disable_resources(struct pci_dev *pdev,
-+ unsigned int rsrc,
-+ unsigned int change_bridge)
-+{
-+ struct pci_bus *bus;
-+ struct pci_dev *bridge;
-+ u16 cmd;
-+
-+ pr_devel("%s\n", __func__);
-+
-+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-+ if (rsrc & (VGA_RSRC_LEGACY_IO | VGA_RSRC_NORMAL_IO))
-+ cmd &= ~PCI_COMMAND_IO;
-+ if (rsrc & (VGA_RSRC_LEGACY_MEM | VGA_RSRC_NORMAL_MEM))
-+ cmd &= ~PCI_COMMAND_MEMORY;
-+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
-+
-+ if (!change_bridge)
-+ return;
-+
-+ bus = pdev->bus;
-+ while (bus) {
-+ bridge = bus->self;
-+ if (bridge) {
-+ pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
-+ &cmd);
-+ if (cmd & PCI_BRIDGE_CTL_VGA) {
-+ cmd &= ~PCI_BRIDGE_CTL_VGA;
-+ pci_write_config_word(bridge,
-+ PCI_BRIDGE_CONTROL,
-+ cmd);
-+ }
-+ }
-+ bus = bus->parent;
-+ }
-+}
-+#endif
-+
-+#ifndef __ARCH_HAS_VGA_ENABLE_RESOURCES
-+static inline void vga_enable_resources(struct pci_dev *pdev,
-+ unsigned int rsrc)
-+{
-+ struct pci_bus *bus;
-+ struct pci_dev *bridge;
-+ u16 cmd;
-+
-+ pr_devel("%s\n", __func__);
-+
-+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-+ if (rsrc & (VGA_RSRC_LEGACY_IO | VGA_RSRC_NORMAL_IO))
-+ cmd |= PCI_COMMAND_IO;
-+ if (rsrc & (VGA_RSRC_LEGACY_MEM | VGA_RSRC_NORMAL_MEM))
-+ cmd |= PCI_COMMAND_MEMORY;
-+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
-+
-+ if (!(rsrc & VGA_RSRC_LEGACY_MASK))
-+ return;
-+
-+ bus = pdev->bus;
-+ while (bus) {
-+ bridge = bus->self;
-+ if (bridge) {
-+ pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
-+ &cmd);
-+ if (!(cmd & PCI_BRIDGE_CTL_VGA)) {
-+ cmd |= PCI_BRIDGE_CTL_VGA;
-+ pci_write_config_word(bridge,
-+ PCI_BRIDGE_CONTROL,
-+ cmd);
-+ }
-+ }
-+ bus = bus->parent;
-+ }
-+}
-+#endif
+
+static struct vga_device *__vga_tryget(struct vga_device *vgadev,
+ unsigned int rsrc)
+{
+ unsigned int wants, legacy_wants, match;
+ struct vga_device *conflict;
-+
++ unsigned int pci_bits;
+ /* Account for "normal" resources to lock. If we decode the legacy,
+ * counterpart, we need to request it as well
+ */
@@ -304,8 +261,15 @@ index 0000000..09cf259
+ * them from him
+ */
+ vga_irq_set_state(conflict, false);
-+ vga_disable_resources(conflict->pdev, lwants,
-+ change_bridge);
++
++ pci_bits = 0;
++ if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
++ pci_bits |= PCI_COMMAND_MEMORY;
++ if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
++ pci_bits |= PCI_COMMAND_IO;
++
++ pci_set_vga_state(conflict->pdev, false, pci_bits,
++ change_bridge);
+ conflict->owns &= ~lwants;
+ /* If he also owned non-legacy, that is no longer the case */
+ if (lwants & VGA_RSRC_LEGACY_MEM)
@@ -320,7 +284,13 @@ index 0000000..09cf259
+ * also have in "decodes". We can lock resources we don't decode but
+ * not own them.
+ */
-+ vga_enable_resources(vgadev->pdev, wants);
++ pci_bits = 0;
++ if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
++ pci_bits |= PCI_COMMAND_MEMORY;
++ if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
++ pci_bits |= PCI_COMMAND_IO;
++ pci_set_vga_state(vgadev->pdev, true, pci_bits, !!(wants & VGA_RSRC_LEGACY_MASK));
++
+ vga_irq_set_state(vgadev, true);
+ vgadev->owns |= (wants & vgadev->decodes);
+lock_them:
@@ -424,6 +394,7 @@ index 0000000..09cf259
+ }
+ return rc;
+}
++EXPORT_SYMBOL(vga_get);
+
+int vga_tryget(struct pci_dev *pdev, unsigned int rsrc)
+{
@@ -448,6 +419,7 @@ index 0000000..09cf259
+ spin_unlock_irqrestore(&vga_lock, flags);
+ return rc;
+}
++EXPORT_SYMBOL(vga_tryget);
+
+void vga_put(struct pci_dev *pdev, unsigned int rsrc)
+{
@@ -467,6 +439,7 @@ index 0000000..09cf259
+bail:
+ spin_unlock_irqrestore(&vga_lock, flags);
+}
++EXPORT_SYMBOL(vga_put);
+
+/*
+ * Currently, we assume that the "initial" setup of the system is
@@ -509,7 +482,7 @@ index 0000000..09cf259
+
+ /* By default, assume we decode everything */
+ vgadev->decodes = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
-+ VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
++ VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+
+ /* Mark that we "own" resources based on our enables, we will
+ * clear that below if the bridge isn't forwarding
@@ -540,16 +513,21 @@ index 0000000..09cf259
+ * by default if arch doesn't have it's own hook
+ */
+#ifndef __ARCH_HAS_VGA_DEFAULT_DEVICE
-+ if (vga_default == NULL && (vgadev->owns & VGA_RSRC_LEGACY_MEM) &&
-+ (vgadev->owns & VGA_RSRC_LEGACY_IO))
-+ vga_default = pdev;
++ if (vga_default == NULL &&
++ ((vgadev->owns & VGA_RSRC_LEGACY_MASK) == VGA_RSRC_LEGACY_MASK))
++ vga_default = pci_dev_get(pdev);
+
+#endif
+
+ /* Add to the list */
+ list_add(&vgadev->list, &vga_list);
-+ pr_info("VGA Arbiter: device added: %d %d %d\n",
-+ pdev->device, pdev->vendor, pdev->devfn);
++ vga_count++;
++ pr_info("vgaarb: device added: PCI:%s,decodes=%s,owns=%s,locks=%s\n",
++ pci_name(pdev),
++ vga_iostate_to_str(vgadev->decodes),
++ vga_iostate_to_str(vgadev->owns),
++ vga_iostate_to_str(vgadev->locks));
++
+ spin_unlock_irqrestore(&vga_lock, flags);
+ return;
+fail:
@@ -567,12 +545,14 @@ index 0000000..09cf259
+ if (vgadev == NULL)
+ goto bail;
+
-+ if (vga_default == pdev)
++ if (vga_default == pdev) {
++ pci_dev_put(vga_default);
+ vga_default = NULL;
++ }
+
+ /* Remove entry from list */
+ list_del(&vgadev->list);
-+
++ vga_count--;
+ /* Notify userland driver that the device is gone so it discards
+ * it's copies of the pci_dev pointer
+ */
@@ -585,10 +565,11 @@ index 0000000..09cf259
+ kfree(vgadev);
+}
+
-+void vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes)
++void __vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes, bool userspace)
+{
+ struct vga_device *vgadev;
+ unsigned long flags;
++ int old_decodes;
+
+ decodes &= VGA_RSRC_LEGACY_MASK;
+
@@ -597,9 +578,19 @@ index 0000000..09cf259
+ if (vgadev == NULL)
+ goto bail;
+
++ /* don't let userspace futz with kernel driver decodes */
++ if (userspace && vgadev->count_notify)
++ goto bail;
++
++ old_decodes = vgadev->decodes;
+ vgadev->decodes = decodes;
+ vgadev->owns &= decodes;
+
++ pr_info("vgaarb: device changed decodes: PCI:%s,olddecodes=%s,decodes=%s\n",
++ pci_name(pdev),
++ vga_iostate_to_str(old_decodes),
++ vga_iostate_to_str(vgadev->decodes));
++
+ /* XXX if somebody is going from "doesn't decode" to "decodes" state
+ * here, additional care must be taken as we may have pending owner
+ * ship of non-legacy region ...
@@ -607,10 +598,20 @@ index 0000000..09cf259
+bail:
+ spin_unlock_irqrestore(&vga_lock, flags);
+}
++
++void vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes)
++{
++ __vga_set_legacy_decoding(pdev, decodes, false);
++}
+EXPORT_SYMBOL(vga_set_legacy_decoding);
+
-+void vga_set_irq_callback(struct pci_dev *pdev, void *cookie, void (*irq_func)(void *cookie, bool enable))
++/* return number of active VGA devices */
++/* call with NULL to unregister */
++int vga_client_register(struct pci_dev *pdev, void *cookie,
++ void (*irq_set_state)(void *cookie, bool state),
++ unsigned int (*count_notify)(void *cookie, int vga_count))
+{
++ int ret = -1;
+ struct vga_device *vgadev;
+ unsigned long flags;
+
@@ -619,13 +620,17 @@ index 0000000..09cf259
+ if (!vgadev)
+ goto bail;
+
-+ vgadev->irq_cookie = cookie;
-+ vgadev->irq_set_state = irq_func;
++ vgadev->irq_set_state = irq_set_state;
++ vgadev->count_notify = count_notify;
++ vgadev->cookie = cookie;
++ ret = vga_count;
++
+bail:
+ spin_unlock_irqrestore(&vga_lock, flags);
++ return ret;
+
+}
-+EXPORT_SYMBOL(vga_set_irq_callback);
++EXPORT_SYMBOL(vga_client_register);
+
+/*
+ * Char driver implementation
@@ -702,36 +707,6 @@ index 0000000..09cf259
+static LIST_HEAD(vga_user_list);
+static DEFINE_SPINLOCK(vga_user_lock);
+
-+static const char *vga_iostate_to_str(unsigned int iostate)
-+{
-+ /* Ignore VGA_RSRC_IO and VGA_RSRC_MEM */
-+ iostate &= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
-+ switch (iostate) {
-+ case VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM:
-+ return "io+mem";
-+ case VGA_RSRC_LEGACY_IO:
-+ return "io";
-+ case VGA_RSRC_LEGACY_MEM:
-+ return "mem";
-+ }
-+ return "none";
-+}
-+
-+static int vga_str_to_iostate(char *buf, int str_size, int *io_state)
-+{
-+ /* XXX We're not chekcing the str_size! */
-+ if (strncmp(buf, "io+mem", 6) == 0)
-+ *io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
-+ else if (strncmp(buf, "io", 2) == 0)
-+ *io_state = VGA_RSRC_LEGACY_IO;
-+ else if (strncmp(buf, "mem", 3) == 0)
-+ *io_state = VGA_RSRC_LEGACY_MEM;
-+ else if (strncmp(buf, "none", 4) == 0)
-+ *io_state = VGA_RSRC_NONE;
-+ else
-+ return 0;
-+ return 1;
-+}
+
+/*
+ * This function gets a string in the format: "PCI:domain:bus:dev.fn" and
@@ -796,8 +771,8 @@ index 0000000..09cf259
+
+ /* Fill the buffer with infos */
+ len = snprintf(lbuf, 1024,
-+ "PCI:%s,decodes=%s,owns=%s,locks=%s (%d,%d)\n",
-+ pci_name(pdev),
++ "count:%d PCI:%s,decodes=%s,owns=%s,locks=%s (%d,%d)\n",
++ vga_count, pci_name(pdev),
+ vga_iostate_to_str(vgadev->decodes),
+ vga_iostate_to_str(vgadev->owns),
+ vga_iostate_to_str(vgadev->locks),
@@ -824,6 +799,7 @@ index 0000000..09cf259
+ size_t count, loff_t *ppos)
+{
+ struct vga_arb_private *priv = file->private_data;
++ struct vga_arb_user_card *uc = NULL;
+ struct pci_dev *pdev;
+
+ unsigned int io_state;
@@ -861,9 +837,11 @@ index 0000000..09cf259
+ goto done;
+ }
+
++
++
+ pdev = priv->target;
+ if (priv->target == NULL) {
-+ ret_val = -ENODEV;
++ ret_val = -ENODEV;
+ goto done;
+ }
+
@@ -909,18 +887,27 @@ index 0000000..09cf259
+ ret_val = -ENODEV;
+ goto done;
+ }
-+
-+ vga_put(pdev, io_state);
+ for (i = 0; i < MAX_USER_CARDS; i++) {
-+ if (priv->cards[i].pdev == pdev) {
-+ if (io_state & VGA_RSRC_LEGACY_IO)
-+ priv->cards[i].io_cnt--;
-+ if (io_state & VGA_RSRC_LEGACY_MEM)
-+ priv->cards[i].mem_cnt--;
-+ break;
-+ }
++ if (priv->cards[i].pdev == pdev)
++ uc = &priv->cards[i];
+ }
+
++ if (!uc)
++ return -EINVAL;
++
++ if (io_state & VGA_RSRC_LEGACY_IO && uc->io_cnt == 0)
++ return -EINVAL;
++
++ if (io_state & VGA_RSRC_LEGACY_MEM && uc->mem_cnt == 0)
++ return -EINVAL;
++
++ vga_put(pdev, io_state);
++
++ if (io_state & VGA_RSRC_LEGACY_IO)
++ uc->io_cnt--;
++ if (io_state & VGA_RSRC_LEGACY_MEM)
++ uc->mem_cnt--;
++
+ ret_val = count;
+ goto done;
+ } else if (strncmp(curr_pos, "trylock ", 8) == 0) {
@@ -979,14 +966,14 @@ index 0000000..09cf259
+
+ pdev = pci_get_bus_and_slot(bus, devfn);
+ if (!pdev) {
-+ pr_info("Invalid pci address!\n");
++ pr_info("vgaarb: invalid PCI address!\n");
+ ret_val = -ENODEV;
+ goto done;
+ }
+
+ vgadev = vgadev_find(pdev);
+ if (vgadev == NULL) {
-+ pr_info("This PCI is not a vga device\n");
++ pr_info("vgaarb: this pci device is not a vga device\n");
+ ret_val = -ENODEV;
+ goto done;
+ }
@@ -1003,7 +990,7 @@ index 0000000..09cf259
+ }
+ }
+ if (i == MAX_USER_CARDS) {
-+ pr_err("Maximum user cards number reached!\n");
++ pr_err("vgaarb: maximum user cards number reached!\n");
+ /* XXX: which value to return? */
+ ret_val = -ENOMEM;
+ goto done;
@@ -1016,7 +1003,7 @@ index 0000000..09cf259
+ } else if (strncmp(curr_pos, "decodes ", 8) == 0) {
+ curr_pos += 8;
+ remaining -= 8;
-+ pr_devel("client 0x%X called 'decodes'\n", (int)priv);
++ pr_devel("vgaarb: client 0x%X called 'decodes'\n", (int)priv);
+
+ if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) {
+ ret_val = -EPROTO;
@@ -1024,11 +1011,11 @@ index 0000000..09cf259
+ }
+ pdev = priv->target;
+ if (priv->target == NULL) {
-+ ret_val = -ENODEV;
++ ret_val = -ENODEV;
+ goto done;
+ }
+
-+ vga_set_legacy_decoding(pdev, io_state);
++ __vga_set_legacy_decoding(pdev, io_state, true);
+ ret_val = count;
+ goto done;
+ }
@@ -1045,7 +1032,7 @@ index 0000000..09cf259
+{
+ struct vga_arb_private *priv = file->private_data;
+
-+ pr_devel("vga_arb_fpoll()\n");
++ pr_devel("%s\n", __func__);
+
+ if (priv == NULL)
+ return -ENODEV;
@@ -1058,7 +1045,7 @@ index 0000000..09cf259
+ struct vga_arb_private *priv;
+ unsigned long flags;
+
-+ pr_devel("vga_arb_open()\n");
++ pr_devel("%s\n", __func__);
+
+ priv = kmalloc(sizeof(struct vga_arb_private), GFP_KERNEL);
+ if (priv == NULL)
@@ -1088,7 +1075,7 @@ index 0000000..09cf259
+ unsigned long flags;
+ int i;
+
-+ pr_devel("vga_arb_release()\n");
++ pr_devel("%s\n", __func__);
+
+ if (priv == NULL)
+ return -ENODEV;
@@ -1117,13 +1104,34 @@ index 0000000..09cf259
+{
+}
+
++/*
++ * callback any registered clients to let them know we have a
++ * change in VGA cards
++ */
++static void vga_arbiter_notify_clients(void)
++{
++ struct vga_device *vgadev;
++ unsigned long flags;
++ uint32_t new_decodes;
++
++ spin_lock_irqsave(&vga_lock, flags);
++ list_for_each_entry(vgadev, &vga_list, list) {
++ if (vgadev->count_notify) {
++ new_decodes = vgadev->count_notify(vgadev->cookie, vga_count);
++ vgadev->decodes = new_decodes;
++ vgadev->owns &= new_decodes;
++ }
++ }
++ spin_unlock_irqrestore(&vga_lock, flags);
++}
++
+static int pci_notify(struct notifier_block *nb, unsigned long action,
+ void *data)
+{
+ struct device *dev = data;
+ struct pci_dev *pdev = to_pci_dev(dev);
+
-+ pr_devel("pci_notify()\n");
++ pr_devel("%s\n", __func__);
+
+ /* For now we're only intereted in devices added and removed. I didn't
+ * test this thing here, so someone needs to double check for the
@@ -1133,6 +1141,7 @@ index 0000000..09cf259
+ else if (action == BUS_NOTIFY_DEL_DEVICE)
+ vga_arbiter_del_pci_device(pdev);
+
++ vga_arbiter_notify_clients();
+ return 0;
+}
+
@@ -1159,7 +1168,7 @@ index 0000000..09cf259
+
+ rc = misc_register(&vga_arb_device);
+ if (rc < 0)
-+ pr_err("VGA Arbiter: error %d registering device\n", rc);
++ pr_err("vgaarb: error %d registering device\n", rc);
+
+ bus_register_notifier(&pci_bus_type, &pci_notifier);
+
@@ -1171,10 +1180,65 @@ index 0000000..09cf259
+ PCI_ANY_ID, pdev)) != NULL)
+ vga_arbiter_add_pci_device(pdev);
+
-+ pr_info("VGA Arbiter: loaded\n");
++ pr_info("vgaarb: loaded\n");
+ return rc;
+}
+subsys_initcall(vga_arb_device_init);
+diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
+index dbd0f94..d837606 100644
+--- a/drivers/pci/pci.c
++++ b/drivers/pci/pci.c
+@@ -2502,6 +2502,50 @@ int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
+ return 0;
+ }
+
++/**
++ * pci_set_vga_state - set VGA decode state on device and parents if requested
++ * @dev the PCI device
++ * @decode - true = enable decoding, false = disable decoding
++ * @command_bits PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY
++ * @change_bridge - traverse ancestors and change bridges
++ */
++int pci_set_vga_state(struct pci_dev *dev, bool decode,
++ unsigned int command_bits, bool change_bridge)
++{
++ struct pci_bus *bus;
++ struct pci_dev *bridge;
++ u16 cmd;
++
++ WARN_ON(command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
++
++ pci_read_config_word(dev, PCI_COMMAND, &cmd);
++ if (decode == true)
++ cmd |= command_bits;
++ else
++ cmd &= ~command_bits;
++ pci_write_config_word(dev, PCI_COMMAND, cmd);
++
++ if (change_bridge == false)
++ return 0;
++
++ bus = dev->bus;
++ while (bus) {
++ bridge = bus->self;
++ if (bridge) {
++ pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
++ &cmd);
++ if (decode == true)
++ cmd |= PCI_BRIDGE_CTL_VGA;
++ else
++ cmd &= ~PCI_BRIDGE_CTL_VGA;
++ pci_write_config_word(bridge, PCI_BRIDGE_CONTROL,
++ cmd);
++ }
++ bus = bus->parent;
++ }
++ return 0;
++}
++
+ #define RESOURCE_ALIGNMENT_PARAM_SIZE COMMAND_LINE_SIZE
+ static char resource_alignment_param[RESOURCE_ALIGNMENT_PARAM_SIZE] = {0};
+ spinlock_t resource_alignment_lock = SPIN_LOCK_UNLOCKED;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 8afcf08..f4ed145 100644
--- a/drivers/video/Kconfig
@@ -1188,12 +1252,25 @@ index 8afcf08..f4ed145 100644
source "drivers/gpu/drm/Kconfig"
config VGASTATE
+diff --git a/include/linux/pci.h b/include/linux/pci.h
+index 115fb7b..7ba6eba 100644
+--- a/include/linux/pci.h
++++ b/include/linux/pci.h
+@@ -805,6 +805,8 @@ int pci_cfg_space_size_ext(struct pci_dev *dev);
+ int pci_cfg_space_size(struct pci_dev *dev);
+ unsigned char pci_bus_max_busnr(struct pci_bus *bus);
+
++int pci_set_vga_state(struct pci_dev *pdev, bool decode,
++ unsigned int command_bits, bool change_bridge);
+ /* kmem_cache style wrapper around pci_alloc_consistent() */
+
+ #include <linux/dmapool.h>
diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h
new file mode 100644
-index 0000000..cdc4ebb
+index 0000000..229561d
--- /dev/null
+++ b/include/linux/vgaarb.h
-@@ -0,0 +1,170 @@
+@@ -0,0 +1,198 @@
+/*
+ * vgaarb.c
+ *
@@ -1361,7 +1438,35 @@ index 0000000..cdc4ebb
+}
+#endif
+
-+void vga_set_irq_callback(struct pci_dev *pdev, void *cookie, void (*irq_func)(void *cookie, bool enable));
++/*
++ * Register a client with the VGA arbitration logic
++ * return value: number of VGA devices in system.
++ *
++ * Clients have two callback mechanisms they can use.
++ * irq enable/disable callback -
++ * If a client can't disable its GPUs VGA resources, then we
++ * need to be able to ask it to turn off its irqs when we
++ * turn off its mem and io decoding.
++ * count_notify -
++ * If a client can disable its GPU VGA resource, it will
++ * get a count_notify callback everytime a new VGA device shows
++ * up in the system via hotplug. The client is expected to
++ * disable VGA legacy decoding if the VGA device goes above 1.
++ * It can re-enable VGA decoding if the number of devices goes to 0
++ *
++ * Clients with disable abilities should check the return value
++ * of this function and if the VGA device count is > 1, should
++ * disable VGA decoding resources.
++ *
++ * Rationale: we cannot disable VGA decode resources unconditionally
++ * some single GPU laptops seem to require ACPI or BIOS access to the
++ * VGA registers to control things like backlights etc.
++ * Hopefully newer multi-GPU laptops do something saner, and desktops
++ * won't have any special ACPI for this.
++ */
++int vga_client_register(struct pci_dev *pdev, void *cookie,
++ void (*irq_set_state)(void *cookie, bool state),
++ unsigned int (*count_notify)(void *cookie, int vga_count));
+
+#endif /* LINUX_VGA_H */
--
More information about the fedora-extras-commits
mailing list