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