Skip to content
This repository has been archived by the owner on Sep 30, 2019. It is now read-only.

Commit

Permalink
drm/vgaarb: add VGA arbitration support to the drm and kms.
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
airlied committed Sep 21, 2009
1 parent aadd4e1 commit 28d5204
Show file tree
Hide file tree
Showing 13 changed files with 133 additions and 1 deletion.
27 changes: 27 additions & 0 deletions drivers/gpu/drm/drm_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

#include <linux/interrupt.h> /* For task queue support */

#include <linux/vgaarb.h>
/**
* Get interrupt from bus id.
*
Expand Down Expand Up @@ -171,6 +172,26 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs)
}
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.
*
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
20 changes: 20 additions & 0 deletions drivers/gpu/drm/i915/i915_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/i915_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
17 changes: 17 additions & 0 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/intel_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */
14 changes: 14 additions & 0 deletions drivers/gpu/drm/radeon/r100.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
14 changes: 14 additions & 0 deletions drivers/gpu/drm/radeon/r600.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/radeon/r600d.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/radeon/radeon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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))
Expand Down
12 changes: 12 additions & 0 deletions drivers/gpu/drm/radeon/radeon_asic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
21 changes: 20 additions & 1 deletion drivers/gpu/drm/radeon/radeon_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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);
Expand All @@ -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))
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions include/drm/drmP.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit 28d5204

Please sign in to comment.