aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-03-01 01:22:38 -0500
committerDave Airlie <airlied@redhat.com>2010-03-01 01:22:38 -0500
commit1c62233508ef7104f8a78e571fdf5c72d0dc0200 (patch)
tree31e19cbff5c1080d3015d20b24dd43ee95f4ed8c /drivers/gpu
parent6d9c13513661c1991bf5f4e6e1363c721292d819 (diff)
parent6a9ee8af344e3bd7dbd61e67037096cdf7f83289 (diff)
Merge branch 'gpu-switcher' of /ssd/git//linux-2.6 into drm-next-stage
* 'gpu-switcher' of /ssd/git//linux-2.6: vga_switcheroo: initial implementation (v15) fb: for framebuffer handover don't exit the loop early. Conflicts: drivers/gpu/drm/i915/i915_dma.c drivers/gpu/drm/radeon/Makefile drivers/gpu/drm/radeon/radeon.h
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c35
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c4
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c160
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c9
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h19
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c32
-rw-r--r--drivers/gpu/drm/radeon/Makefile2
-rw-r--r--drivers/gpu/drm/radeon/radeon.h8
-rw-r--r--drivers/gpu/drm/radeon/radeon_atpx_handler.c258
-rw-r--r--drivers/gpu/drm/radeon/radeon_bios.c44
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c40
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.h3
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c3
-rw-r--r--drivers/gpu/vga/Kconfig13
-rw-r--r--drivers/gpu/vga/Makefile1
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c453
21 files changed, 1025 insertions, 70 deletions
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 3e658d6a6b7d..8bfc0bbf13e6 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -37,6 +37,7 @@
37#include <linux/vgaarb.h> 37#include <linux/vgaarb.h>
38#include <linux/acpi.h> 38#include <linux/acpi.h>
39#include <linux/pnp.h> 39#include <linux/pnp.h>
40#include <linux/vga_switcheroo.h>
40 41
41/* Really want an OS-independent resettable timer. Would like to have 42/* Really want an OS-independent resettable timer. Would like to have
42 * this loop run for (eg) 3 sec, but have the timer reset every time 43 * this loop run for (eg) 3 sec, but have the timer reset every time
@@ -1381,6 +1382,32 @@ static unsigned int i915_vga_set_decode(void *cookie, bool state)
1381 return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; 1382 return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
1382} 1383}
1383 1384
1385static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
1386{
1387 struct drm_device *dev = pci_get_drvdata(pdev);
1388 pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
1389 if (state == VGA_SWITCHEROO_ON) {
1390 printk(KERN_INFO "i915: switched off\n");
1391 /* i915 resume handler doesn't set to D0 */
1392 pci_set_power_state(dev->pdev, PCI_D0);
1393 i915_resume(dev);
1394 } else {
1395 printk(KERN_ERR "i915: switched off\n");
1396 i915_suspend(dev, pmm);
1397 }
1398}
1399
1400static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
1401{
1402 struct drm_device *dev = pci_get_drvdata(pdev);
1403 bool can_switch;
1404
1405 spin_lock(&dev->count_lock);
1406 can_switch = (dev->open_count == 0);
1407 spin_unlock(&dev->count_lock);
1408 return can_switch;
1409}
1410
1384static int i915_load_modeset_init(struct drm_device *dev, 1411static int i915_load_modeset_init(struct drm_device *dev,
1385 unsigned long prealloc_start, 1412 unsigned long prealloc_start,
1386 unsigned long prealloc_size, 1413 unsigned long prealloc_size,
@@ -1442,6 +1469,12 @@ static int i915_load_modeset_init(struct drm_device *dev,
1442 if (ret) 1469 if (ret)
1443 goto destroy_ringbuffer; 1470 goto destroy_ringbuffer;
1444 1471
1472 ret = vga_switcheroo_register_client(dev->pdev,
1473 i915_switcheroo_set_state,
1474 i915_switcheroo_can_switch);
1475 if (ret)
1476 goto destroy_ringbuffer;
1477
1445 intel_modeset_init(dev); 1478 intel_modeset_init(dev);
1446 1479
1447 ret = drm_irq_install(dev); 1480 ret = drm_irq_install(dev);
@@ -1733,6 +1766,7 @@ int i915_driver_unload(struct drm_device *dev)
1733 dev_priv->child_dev_num = 0; 1766 dev_priv->child_dev_num = 0;
1734 } 1767 }
1735 drm_irq_uninstall(dev); 1768 drm_irq_uninstall(dev);
1769 vga_switcheroo_unregister_client(dev->pdev);
1736 vga_client_register(dev->pdev, NULL, NULL, NULL); 1770 vga_client_register(dev->pdev, NULL, NULL, NULL);
1737 } 1771 }
1738 1772
@@ -1802,6 +1836,7 @@ void i915_driver_lastclose(struct drm_device * dev)
1802 1836
1803 if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) { 1837 if (!dev_priv || drm_core_check_feature(dev, DRIVER_MODESET)) {
1804 drm_fb_helper_restore(); 1838 drm_fb_helper_restore();
1839 vga_switcheroo_process_delayed_switch();
1805 return; 1840 return;
1806 } 1841 }
1807 1842
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 85ad020125c8..1b2e95455c05 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -214,7 +214,7 @@ static int i915_drm_freeze(struct drm_device *dev)
214 return 0; 214 return 0;
215} 215}
216 216
217static int i915_suspend(struct drm_device *dev, pm_message_t state) 217int i915_suspend(struct drm_device *dev, pm_message_t state)
218{ 218{
219 int error; 219 int error;
220 220
@@ -268,7 +268,7 @@ static int i915_drm_thaw(struct drm_device *dev)
268 return error; 268 return error;
269} 269}
270 270
271static int i915_resume(struct drm_device *dev) 271int i915_resume(struct drm_device *dev)
272{ 272{
273 if (pci_enable_device(dev->pdev)) 273 if (pci_enable_device(dev->pdev))
274 return -EIO; 274 return -EIO;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index f97592609da4..979439cfb827 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -773,6 +773,8 @@ extern unsigned int i915_fbpercrtc;
773extern unsigned int i915_powersave; 773extern unsigned int i915_powersave;
774extern unsigned int i915_lvds_downclock; 774extern unsigned int i915_lvds_downclock;
775 775
776extern int i915_suspend(struct drm_device *dev, pm_message_t state);
777extern int i915_resume(struct drm_device *dev);
776extern void i915_save_display(struct drm_device *dev); 778extern void i915_save_display(struct drm_device *dev);
777extern void i915_restore_display(struct drm_device *dev); 779extern void i915_restore_display(struct drm_device *dev);
778extern int i915_master_create(struct drm_device *dev, struct drm_master *master); 780extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index aaabbcbe5905..8cd791dc5b29 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -35,6 +35,7 @@
35#include <linux/delay.h> 35#include <linux/delay.h>
36#include <linux/fb.h> 36#include <linux/fb.h>
37#include <linux/init.h> 37#include <linux/init.h>
38#include <linux/vga_switcheroo.h>
38 39
39#include "drmP.h" 40#include "drmP.h"
40#include "drm.h" 41#include "drm.h"
@@ -235,6 +236,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
235 obj_priv->gtt_offset, fbo); 236 obj_priv->gtt_offset, fbo);
236 237
237 mutex_unlock(&dev->struct_mutex); 238 mutex_unlock(&dev->struct_mutex);
239 vga_switcheroo_client_fb_set(dev->pdev, info);
238 return 0; 240 return 0;
239 241
240out_unpin: 242out_unpin:
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 48227e744753..0e0730a53137 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -11,6 +11,8 @@
11#include "nouveau_drm.h" 11#include "nouveau_drm.h"
12#include "nv50_display.h" 12#include "nv50_display.h"
13 13
14#include <linux/vga_switcheroo.h>
15
14#define NOUVEAU_DSM_SUPPORTED 0x00 16#define NOUVEAU_DSM_SUPPORTED 0x00
15#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00 17#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00
16 18
@@ -28,31 +30,30 @@
28#define NOUVEAU_DSM_POWER_SPEED 0x01 30#define NOUVEAU_DSM_POWER_SPEED 0x01
29#define NOUVEAU_DSM_POWER_STAMINA 0x02 31#define NOUVEAU_DSM_POWER_STAMINA 0x02
30 32
31static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result) 33static struct nouveau_dsm_priv {
32{ 34 bool dsm_detected;
33 static char muid[] = { 35 acpi_handle dhandle;
34 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D, 36 acpi_handle dsm_handle;
35 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4, 37} nouveau_dsm_priv;
36 }; 38
39static const char nouveau_dsm_muid[] = {
40 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
41 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
42};
37 43
38 struct pci_dev *pdev = dev->pdev; 44static int nouveau_dsm(acpi_handle handle, int func, int arg, int *result)
39 struct acpi_handle *handle; 45{
40 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 46 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
41 struct acpi_object_list input; 47 struct acpi_object_list input;
42 union acpi_object params[4]; 48 union acpi_object params[4];
43 union acpi_object *obj; 49 union acpi_object *obj;
44 int err; 50 int err;
45 51
46 handle = DEVICE_ACPI_HANDLE(&pdev->dev);
47
48 if (!handle)
49 return -ENODEV;
50
51 input.count = 4; 52 input.count = 4;
52 input.pointer = params; 53 input.pointer = params;
53 params[0].type = ACPI_TYPE_BUFFER; 54 params[0].type = ACPI_TYPE_BUFFER;
54 params[0].buffer.length = sizeof(muid); 55 params[0].buffer.length = sizeof(nouveau_dsm_muid);
55 params[0].buffer.pointer = (char *)muid; 56 params[0].buffer.pointer = (char *)nouveau_dsm_muid;
56 params[1].type = ACPI_TYPE_INTEGER; 57 params[1].type = ACPI_TYPE_INTEGER;
57 params[1].integer.value = 0x00000102; 58 params[1].integer.value = 0x00000102;
58 params[2].type = ACPI_TYPE_INTEGER; 59 params[2].type = ACPI_TYPE_INTEGER;
@@ -62,7 +63,7 @@ static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
62 63
63 err = acpi_evaluate_object(handle, "_DSM", &input, &output); 64 err = acpi_evaluate_object(handle, "_DSM", &input, &output);
64 if (err) { 65 if (err) {
65 NV_INFO(dev, "failed to evaluate _DSM: %d\n", err); 66 printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
66 return err; 67 return err;
67 } 68 }
68 69
@@ -86,40 +87,119 @@ static int nouveau_dsm(struct drm_device *dev, int func, int arg, int *result)
86 return 0; 87 return 0;
87} 88}
88 89
89int nouveau_hybrid_setup(struct drm_device *dev) 90static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
90{ 91{
91 int result; 92 return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL);
92 93}
93 if (nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STATE, 94
94 &result)) 95static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switcheroo_state state)
95 return -ENODEV; 96{
96 97 int arg;
97 NV_INFO(dev, "_DSM hardware status gave 0x%x\n", result); 98 if (state == VGA_SWITCHEROO_ON)
98 99 arg = NOUVEAU_DSM_POWER_SPEED;
99 if (result) { /* Ensure that the external GPU is enabled */ 100 else
100 nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_SPEED, NULL); 101 arg = NOUVEAU_DSM_POWER_STAMINA;
101 nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_SPEED, 102 nouveau_dsm(handle, NOUVEAU_DSM_POWER, arg, NULL);
102 NULL); 103 return 0;
103 } else { /* Stamina mode - disable the external GPU */ 104}
104 nouveau_dsm(dev, NOUVEAU_DSM_LED, NOUVEAU_DSM_LED_STAMINA, 105
105 NULL); 106static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
106 nouveau_dsm(dev, NOUVEAU_DSM_POWER, NOUVEAU_DSM_POWER_STAMINA, 107{
107 NULL); 108 if (id == VGA_SWITCHEROO_IGD)
108 } 109 return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_STAMINA);
110 else
111 return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_SPEED);
112}
109 113
114static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
115 enum vga_switcheroo_state state)
116{
117 if (id == VGA_SWITCHEROO_IGD)
118 return 0;
119
120 return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dsm_handle, state);
121}
122
123static int nouveau_dsm_init(void)
124{
110 return 0; 125 return 0;
111} 126}
112 127
113bool nouveau_dsm_probe(struct drm_device *dev) 128static int nouveau_dsm_get_client_id(struct pci_dev *pdev)
114{ 129{
115 int support = 0; 130 if (nouveau_dsm_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
131 return VGA_SWITCHEROO_IGD;
132 else
133 return VGA_SWITCHEROO_DIS;
134}
135
136static struct vga_switcheroo_handler nouveau_dsm_handler = {
137 .switchto = nouveau_dsm_switchto,
138 .power_state = nouveau_dsm_power_state,
139 .init = nouveau_dsm_init,
140 .get_client_id = nouveau_dsm_get_client_id,
141};
116 142
117 if (nouveau_dsm(dev, NOUVEAU_DSM_SUPPORTED, 143static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
118 NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &support)) 144{
145 acpi_handle dhandle, nvidia_handle;
146 acpi_status status;
147 int ret;
148 uint32_t result;
149
150 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
151 if (!dhandle)
152 return false;
153 status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle);
154 if (ACPI_FAILURE(status)) {
119 return false; 155 return false;
156 }
120 157
121 if (!support) 158 ret= nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED,
159 NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
160 if (ret < 0)
122 return false; 161 return false;
123 162
163 nouveau_dsm_priv.dhandle = dhandle;
164 nouveau_dsm_priv.dsm_handle = nvidia_handle;
124 return true; 165 return true;
125} 166}
167
168static bool nouveau_dsm_detect(void)
169{
170 char acpi_method_name[255] = { 0 };
171 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
172 struct pci_dev *pdev = NULL;
173 int has_dsm = 0;
174 int vga_count = 0;
175 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
176 vga_count++;
177
178 has_dsm |= (nouveau_dsm_pci_probe(pdev) == true);
179 }
180
181 if (vga_count == 2 && has_dsm) {
182 acpi_get_name(nouveau_dsm_priv.dsm_handle, ACPI_FULL_PATHNAME, &buffer);
183 printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
184 acpi_method_name);
185 nouveau_dsm_priv.dsm_detected = true;
186 return true;
187 }
188 return false;
189}
190
191void nouveau_register_dsm_handler(void)
192{
193 bool r;
194
195 r = nouveau_dsm_detect();
196 if (!r)
197 return;
198
199 vga_switcheroo_register_handler(&nouveau_dsm_handler);
200}
201
202void nouveau_unregister_dsm_handler(void)
203{
204 vga_switcheroo_unregister_handler();
205}
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 874adf55a43f..30cc09e8a709 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -135,7 +135,7 @@ nouveau_pci_remove(struct pci_dev *pdev)
135 drm_put_dev(dev); 135 drm_put_dev(dev);
136} 136}
137 137
138static int 138int
139nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) 139nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
140{ 140{
141 struct drm_device *dev = pci_get_drvdata(pdev); 141 struct drm_device *dev = pci_get_drvdata(pdev);
@@ -233,7 +233,7 @@ out_abort:
233 return ret; 233 return ret;
234} 234}
235 235
236static int 236int
237nouveau_pci_resume(struct pci_dev *pdev) 237nouveau_pci_resume(struct pci_dev *pdev)
238{ 238{
239 struct drm_device *dev = pci_get_drvdata(pdev); 239 struct drm_device *dev = pci_get_drvdata(pdev);
@@ -402,8 +402,10 @@ static int __init nouveau_init(void)
402 nouveau_modeset = 1; 402 nouveau_modeset = 1;
403 } 403 }
404 404
405 if (nouveau_modeset == 1) 405 if (nouveau_modeset == 1) {
406 driver.driver_features |= DRIVER_MODESET; 406 driver.driver_features |= DRIVER_MODESET;
407 nouveau_register_dsm_handler();
408 }
407 409
408 return drm_init(&driver); 410 return drm_init(&driver);
409} 411}
@@ -411,6 +413,7 @@ static int __init nouveau_init(void)
411static void __exit nouveau_exit(void) 413static void __exit nouveau_exit(void)
412{ 414{
413 drm_exit(&driver); 415 drm_exit(&driver);
416 nouveau_unregister_dsm_handler();
414} 417}
415 418
416module_init(nouveau_init); 419module_init(nouveau_init);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 2f8ce42f0725..a2e24f252e84 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -622,7 +622,6 @@ struct drm_nouveau_private {
622 } susres; 622 } susres;
623 623
624 struct backlight_device *backlight; 624 struct backlight_device *backlight;
625 bool acpi_dsm;
626 625
627 struct nouveau_channel *evo; 626 struct nouveau_channel *evo;
628 627
@@ -690,6 +689,9 @@ extern int nouveau_ignorelid;
690extern int nouveau_nofbaccel; 689extern int nouveau_nofbaccel;
691extern int nouveau_noaccel; 690extern int nouveau_noaccel;
692 691
692extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state);
693extern int nouveau_pci_resume(struct pci_dev *pdev);
694
693/* nouveau_state.c */ 695/* nouveau_state.c */
694extern void nouveau_preclose(struct drm_device *dev, struct drm_file *); 696extern void nouveau_preclose(struct drm_device *dev, struct drm_file *);
695extern int nouveau_load(struct drm_device *, unsigned long flags); 697extern int nouveau_load(struct drm_device *, unsigned long flags);
@@ -850,19 +852,8 @@ extern int nouveau_dma_init(struct nouveau_channel *);
850extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size); 852extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
851 853
852/* nouveau_acpi.c */ 854/* nouveau_acpi.c */
853#ifdef CONFIG_ACPI 855void nouveau_register_dsm_handler(void);
854extern int nouveau_hybrid_setup(struct drm_device *dev); 856void nouveau_unregister_dsm_handler(void);
855extern bool nouveau_dsm_probe(struct drm_device *dev);
856#else
857static inline int nouveau_hybrid_setup(struct drm_device *dev)
858{
859 return 0;
860}
861static inline bool nouveau_dsm_probe(struct drm_device *dev)
862{
863 return false;
864}
865#endif
866 857
867/* nouveau_backlight.c */ 858/* nouveau_backlight.c */
868#ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT 859#ifdef CONFIG_DRM_NOUVEAU_BACKLIGHT
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index d48c59cdefe4..68cedd9194fe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -36,6 +36,7 @@
36#include <linux/fb.h> 36#include <linux/fb.h>
37#include <linux/init.h> 37#include <linux/init.h>
38#include <linux/screen_info.h> 38#include <linux/screen_info.h>
39#include <linux/vga_switcheroo.h>
39 40
40#include "drmP.h" 41#include "drmP.h"
41#include "drm.h" 42#include "drm.h"
@@ -370,6 +371,7 @@ nouveau_fbcon_create(struct drm_device *dev, uint32_t fb_width,
370 nvbo->bo.offset, nvbo); 371 nvbo->bo.offset, nvbo);
371 372
372 mutex_unlock(&dev->struct_mutex); 373 mutex_unlock(&dev->struct_mutex);
374 vga_switcheroo_client_fb_set(dev->pdev, info);
373 return 0; 375 return 0;
374 376
375out_unref: 377out_unref:
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 516a8d36cb10..eb8f084d5f53 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -29,6 +29,7 @@
29#include "drm_sarea.h" 29#include "drm_sarea.h"
30#include "drm_crtc_helper.h" 30#include "drm_crtc_helper.h"
31#include <linux/vgaarb.h> 31#include <linux/vgaarb.h>
32#include <linux/vga_switcheroo.h>
32 33
33#include "nouveau_drv.h" 34#include "nouveau_drv.h"
34#include "nouveau_drm.h" 35#include "nouveau_drm.h"
@@ -371,6 +372,30 @@ out_err:
371 return ret; 372 return ret;
372} 373}
373 374
375static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
376 enum vga_switcheroo_state state)
377{
378 pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
379 if (state == VGA_SWITCHEROO_ON) {
380 printk(KERN_ERR "VGA switcheroo: switched nouveau on\n");
381 nouveau_pci_resume(pdev);
382 } else {
383 printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
384 nouveau_pci_suspend(pdev, pmm);
385 }
386}
387
388static bool nouveau_switcheroo_can_switch(struct pci_dev *pdev)
389{
390 struct drm_device *dev = pci_get_drvdata(pdev);
391 bool can_switch;
392
393 spin_lock(&dev->count_lock);
394 can_switch = (dev->open_count == 0);
395 spin_unlock(&dev->count_lock);
396 return can_switch;
397}
398
374int 399int
375nouveau_card_init(struct drm_device *dev) 400nouveau_card_init(struct drm_device *dev)
376{ 401{
@@ -384,6 +409,8 @@ nouveau_card_init(struct drm_device *dev)
384 return 0; 409 return 0;
385 410
386 vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); 411 vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
412 vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
413 nouveau_switcheroo_can_switch);
387 414
388 /* Initialise internal driver API hooks */ 415 /* Initialise internal driver API hooks */
389 ret = nouveau_init_engine_ptrs(dev); 416 ret = nouveau_init_engine_ptrs(dev);
@@ -618,11 +645,6 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
618 NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n", 645 NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n",
619 dev->pci_vendor, dev->pci_device, dev->pdev->class); 646 dev->pci_vendor, dev->pci_device, dev->pdev->class);
620 647
621 dev_priv->acpi_dsm = nouveau_dsm_probe(dev);
622
623 if (dev_priv->acpi_dsm)
624 nouveau_hybrid_setup(dev);
625
626 dev_priv->wq = create_workqueue("nouveau"); 648 dev_priv->wq = create_workqueue("nouveau");
627 if (!dev_priv->wq) 649 if (!dev_priv->wq)
628 return -EINVAL; 650 return -EINVAL;
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index b46f115d1c25..0a4d526e4f44 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -60,7 +60,7 @@ radeon-y += radeon_device.o radeon_kms.o \
60 rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \ 60 rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
61 r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ 61 r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
62 r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \ 62 r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
63 evergreen.o 63 evergreen.o radeon_atpx_handler.o
64 64
65radeon-$(CONFIG_COMPAT) += radeon_ioc32.o 65radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
66 66
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 2434d553bbbc..ad9d55f94398 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -119,6 +119,10 @@ struct radeon_device;
119/* 119/*
120 * BIOS. 120 * BIOS.
121 */ 121 */
122#define ATRM_BIOS_PAGE 4096
123
124bool radeon_atrm_supported(struct pci_dev *pdev);
125int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len);
122bool radeon_get_bios(struct radeon_device *rdev); 126bool radeon_get_bios(struct radeon_device *rdev);
123 127
124 128
@@ -957,6 +961,8 @@ struct radeon_device {
957 int audio_bits_per_sample; 961 int audio_bits_per_sample;
958 uint8_t audio_status_bits; 962 uint8_t audio_status_bits;
959 uint8_t audio_category_code; 963 uint8_t audio_category_code;
964
965 bool powered_down;
960}; 966};
961 967
962int radeon_device_init(struct radeon_device *rdev, 968int radeon_device_init(struct radeon_device *rdev,
@@ -1167,6 +1173,8 @@ extern void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain);
1167extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo); 1173extern bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo);
1168extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base); 1174extern void radeon_vram_location(struct radeon_device *rdev, struct radeon_mc *mc, u64 base);
1169extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); 1175extern void radeon_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc);
1176extern int radeon_resume_kms(struct drm_device *dev);
1177extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state);
1170 1178
1171/* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ 1179/* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */
1172struct r100_mc_save { 1180struct r100_mc_save {
diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
new file mode 100644
index 000000000000..0ae52f19071d
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c
@@ -0,0 +1,258 @@
1/*
2 * Copyright (c) 2010 Red Hat Inc.
3 * Author : Dave Airlie <airlied@redhat.com>
4 *
5 * Licensed under GPLv2
6 *
7 * ATPX support for both Intel/ATI
8 */
9
10#include <linux/vga_switcheroo.h>
11#include <acpi/acpi.h>
12#include <acpi/acpi_bus.h>
13#include <linux/pci.h>
14
15#define ATPX_VERSION 0
16#define ATPX_GPU_PWR 2
17#define ATPX_MUX_SELECT 3
18
19#define ATPX_INTEGRATED 0
20#define ATPX_DISCRETE 1
21
22#define ATPX_MUX_IGD 0
23#define ATPX_MUX_DISCRETE 1
24
25static struct radeon_atpx_priv {
26 bool atpx_detected;
27 /* handle for device - and atpx */
28 acpi_handle dhandle;
29 acpi_handle atpx_handle;
30 acpi_handle atrm_handle;
31} radeon_atpx_priv;
32
33/* retrieve the ROM in 4k blocks */
34static int radeon_atrm_call(acpi_handle atrm_handle, uint8_t *bios,
35 int offset, int len)
36{
37 acpi_status status;
38 union acpi_object atrm_arg_elements[2], *obj;
39 struct acpi_object_list atrm_arg;
40 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
41
42 atrm_arg.count = 2;
43 atrm_arg.pointer = &atrm_arg_elements[0];
44
45 atrm_arg_elements[0].type = ACPI_TYPE_INTEGER;
46 atrm_arg_elements[0].integer.value = offset;
47
48 atrm_arg_elements[1].type = ACPI_TYPE_INTEGER;
49 atrm_arg_elements[1].integer.value = len;
50
51 status = acpi_evaluate_object(atrm_handle, NULL, &atrm_arg, &buffer);
52 if (ACPI_FAILURE(status)) {
53 printk("failed to evaluate ATRM got %s\n", acpi_format_exception(status));
54 return -ENODEV;
55 }
56
57 obj = (union acpi_object *)buffer.pointer;
58 memcpy(bios+offset, obj->buffer.pointer, len);
59 kfree(buffer.pointer);
60 return len;
61}
62
63bool radeon_atrm_supported(struct pci_dev *pdev)
64{
65 /* get the discrete ROM only via ATRM */
66 if (!radeon_atpx_priv.atpx_detected)
67 return false;
68
69 if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
70 return false;
71 return true;
72}
73
74
75int radeon_atrm_get_bios_chunk(uint8_t *bios, int offset, int len)
76{
77 return radeon_atrm_call(radeon_atpx_priv.atrm_handle, bios, offset, len);
78}
79
80static int radeon_atpx_get_version(acpi_handle handle)
81{
82 acpi_status status;
83 union acpi_object atpx_arg_elements[2], *obj;
84 struct acpi_object_list atpx_arg;
85 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
86
87 atpx_arg.count = 2;
88 atpx_arg.pointer = &atpx_arg_elements[0];
89
90 atpx_arg_elements[0].type = ACPI_TYPE_INTEGER;
91 atpx_arg_elements[0].integer.value = ATPX_VERSION;
92
93 atpx_arg_elements[1].type = ACPI_TYPE_INTEGER;
94 atpx_arg_elements[1].integer.value = ATPX_VERSION;
95
96 status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer);
97 if (ACPI_FAILURE(status)) {
98 printk("%s: failed to call ATPX: %s\n", __func__, acpi_format_exception(status));
99 return -ENOSYS;
100 }
101 obj = (union acpi_object *)buffer.pointer;
102 if (obj && (obj->type == ACPI_TYPE_BUFFER))
103 printk(KERN_INFO "radeon atpx: version is %d\n", *((u8 *)(obj->buffer.pointer) + 2));
104 kfree(buffer.pointer);
105 return 0;
106}
107
108static int radeon_atpx_execute(acpi_handle handle, int cmd_id, u16 value)
109{
110 acpi_status status;
111 union acpi_object atpx_arg_elements[2];
112 struct acpi_object_list atpx_arg;
113 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
114 uint8_t buf[4] = {0};
115
116 if (!handle)
117 return -EINVAL;
118
119 atpx_arg.count = 2;
120 atpx_arg.pointer = &atpx_arg_elements[0];
121
122 atpx_arg_elements[0].type = ACPI_TYPE_INTEGER;
123 atpx_arg_elements[0].integer.value = cmd_id;
124
125 buf[2] = value & 0xff;
126 buf[3] = (value >> 8) & 0xff;
127
128 atpx_arg_elements[1].type = ACPI_TYPE_BUFFER;
129 atpx_arg_elements[1].buffer.length = 4;
130 atpx_arg_elements[1].buffer.pointer = buf;
131
132 status = acpi_evaluate_object(handle, NULL, &atpx_arg, &buffer);
133 if (ACPI_FAILURE(status)) {
134 printk("%s: failed to call ATPX: %s\n", __func__, acpi_format_exception(status));
135 return -ENOSYS;
136 }
137 kfree(buffer.pointer);
138
139 return 0;
140}
141
142static int radeon_atpx_set_discrete_state(acpi_handle handle, int state)
143{
144 return radeon_atpx_execute(handle, ATPX_GPU_PWR, state);
145}
146
147static int radeon_atpx_switch_mux(acpi_handle handle, int mux_id)
148{
149 return radeon_atpx_execute(handle, ATPX_MUX_SELECT, mux_id);
150}
151
152
153static int radeon_atpx_switchto(enum vga_switcheroo_client_id id)
154{
155 if (id == VGA_SWITCHEROO_IGD)
156 radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 0);
157 else
158 radeon_atpx_switch_mux(radeon_atpx_priv.atpx_handle, 1);
159 return 0;
160}
161
162static int radeon_atpx_power_state(enum vga_switcheroo_client_id id,
163 enum vga_switcheroo_state state)
164{
165 /* on w500 ACPI can't change intel gpu state */
166 if (id == VGA_SWITCHEROO_IGD)
167 return 0;
168
169 radeon_atpx_set_discrete_state(radeon_atpx_priv.atpx_handle, state);
170 return 0;
171}
172
173static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev)
174{
175 acpi_handle dhandle, atpx_handle, atrm_handle;
176 acpi_status status;
177
178 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
179 if (!dhandle)
180 return false;
181
182 status = acpi_get_handle(dhandle, "ATPX", &atpx_handle);
183 if (ACPI_FAILURE(status))
184 return false;
185
186 status = acpi_get_handle(dhandle, "ATRM", &atrm_handle);
187 if (ACPI_FAILURE(status))
188 return false;
189
190 radeon_atpx_priv.dhandle = dhandle;
191 radeon_atpx_priv.atpx_handle = atpx_handle;
192 radeon_atpx_priv.atrm_handle = atrm_handle;
193 return true;
194}
195
196static int radeon_atpx_init(void)
197{
198 /* set up the ATPX handle */
199
200 radeon_atpx_get_version(radeon_atpx_priv.atpx_handle);
201 return 0;
202}
203
204static int radeon_atpx_get_client_id(struct pci_dev *pdev)
205{
206 if (radeon_atpx_priv.dhandle == DEVICE_ACPI_HANDLE(&pdev->dev))
207 return VGA_SWITCHEROO_IGD;
208 else
209 return VGA_SWITCHEROO_DIS;
210}
211
212static struct vga_switcheroo_handler radeon_atpx_handler = {
213 .switchto = radeon_atpx_switchto,
214 .power_state = radeon_atpx_power_state,
215 .init = radeon_atpx_init,
216 .get_client_id = radeon_atpx_get_client_id,
217};
218
219static bool radeon_atpx_detect(void)
220{
221 char acpi_method_name[255] = { 0 };
222 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
223 struct pci_dev *pdev = NULL;
224 bool has_atpx = false;
225 int vga_count = 0;
226
227 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
228 vga_count++;
229
230 has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
231 }
232
233 if (has_atpx && vga_count == 2) {
234 acpi_get_name(radeon_atpx_priv.atpx_handle, ACPI_FULL_PATHNAME, &buffer);
235 printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n",
236 acpi_method_name);
237 radeon_atpx_priv.atpx_detected = true;
238 return true;
239 }
240 return false;
241}
242
243void radeon_register_atpx_handler(void)
244{
245 bool r;
246
247 /* detect if we have any ATPX + 2 VGA in the system */
248 r = radeon_atpx_detect();
249 if (!r)
250 return;
251
252 vga_switcheroo_register_handler(&radeon_atpx_handler);
253}
254
255void radeon_unregister_atpx_handler(void)
256{
257 vga_switcheroo_unregister_handler();
258}
diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index 26856ed8d972..557240460526 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -30,6 +30,7 @@
30#include "radeon.h" 30#include "radeon.h"
31#include "atom.h" 31#include "atom.h"
32 32
33#include <linux/vga_switcheroo.h>
33/* 34/*
34 * BIOS. 35 * BIOS.
35 */ 36 */
@@ -62,7 +63,7 @@ static bool igp_read_bios_from_vram(struct radeon_device *rdev)
62 iounmap(bios); 63 iounmap(bios);
63 return false; 64 return false;
64 } 65 }
65 memcpy(rdev->bios, bios, size); 66 memcpy_fromio(rdev->bios, bios, size);
66 iounmap(bios); 67 iounmap(bios);
67 return true; 68 return true;
68} 69}
@@ -93,6 +94,38 @@ static bool radeon_read_bios(struct radeon_device *rdev)
93 return true; 94 return true;
94} 95}
95 96
97/* ATRM is used to get the BIOS on the discrete cards in
98 * dual-gpu systems.
99 */
100static bool radeon_atrm_get_bios(struct radeon_device *rdev)
101{
102 int ret;
103 int size = 64 * 1024;
104 int i;
105
106 if (!radeon_atrm_supported(rdev->pdev))
107 return false;
108
109 rdev->bios = kmalloc(size, GFP_KERNEL);
110 if (!rdev->bios) {
111 DRM_ERROR("Unable to allocate bios\n");
112 return false;
113 }
114
115 for (i = 0; i < size / ATRM_BIOS_PAGE; i++) {
116 ret = radeon_atrm_get_bios_chunk(rdev->bios,
117 (i * ATRM_BIOS_PAGE),
118 ATRM_BIOS_PAGE);
119 if (ret <= 0)
120 break;
121 }
122
123 if (i == 0 || rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
124 kfree(rdev->bios);
125 return false;
126 }
127 return true;
128}
96static bool r700_read_disabled_bios(struct radeon_device *rdev) 129static bool r700_read_disabled_bios(struct radeon_device *rdev)
97{ 130{
98 uint32_t viph_control; 131 uint32_t viph_control;
@@ -388,16 +421,16 @@ static bool radeon_read_disabled_bios(struct radeon_device *rdev)
388 return legacy_read_disabled_bios(rdev); 421 return legacy_read_disabled_bios(rdev);
389} 422}
390 423
424
391bool radeon_get_bios(struct radeon_device *rdev) 425bool radeon_get_bios(struct radeon_device *rdev)
392{ 426{
393 bool r; 427 bool r;
394 uint16_t tmp; 428 uint16_t tmp;
395 429
396 if (rdev->flags & RADEON_IS_IGP) { 430 r = radeon_atrm_get_bios(rdev);
431 if (r == false)
397 r = igp_read_bios_from_vram(rdev); 432 r = igp_read_bios_from_vram(rdev);
398 if (r == false) 433 if (r == false)
399 r = radeon_read_bios(rdev);
400 } else
401 r = radeon_read_bios(rdev); 434 r = radeon_read_bios(rdev);
402 if (r == false) { 435 if (r == false) {
403 r = radeon_read_disabled_bios(rdev); 436 r = radeon_read_disabled_bios(rdev);
@@ -408,6 +441,7 @@ bool radeon_get_bios(struct radeon_device *rdev)
408 return false; 441 return false;
409 } 442 }
410 if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) { 443 if (rdev->bios[0] != 0x55 || rdev->bios[1] != 0xaa) {
444 printk("BIOS signature incorrect %x %x\n", rdev->bios[0], rdev->bios[1]);
411 goto free_bios; 445 goto free_bios;
412 } 446 }
413 447
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 91a9b966238e..e28e4ed5f720 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -30,6 +30,7 @@
30#include <drm/drm_crtc_helper.h> 30#include <drm/drm_crtc_helper.h>
31#include <drm/radeon_drm.h> 31#include <drm/radeon_drm.h>
32#include <linux/vgaarb.h> 32#include <linux/vgaarb.h>
33#include <linux/vga_switcheroo.h>
33#include "radeon_reg.h" 34#include "radeon_reg.h"
34#include "radeon.h" 35#include "radeon.h"
35#include "radeon_asic.h" 36#include "radeon_asic.h"
@@ -655,6 +656,36 @@ void radeon_check_arguments(struct radeon_device *rdev)
655 } 656 }
656} 657}
657 658
659static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_state state)
660{
661 struct drm_device *dev = pci_get_drvdata(pdev);
662 struct radeon_device *rdev = dev->dev_private;
663 pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
664 if (state == VGA_SWITCHEROO_ON) {
665 printk(KERN_INFO "radeon: switched on\n");
666 /* don't suspend or resume card normally */
667 rdev->powered_down = false;
668 radeon_resume_kms(dev);
669 } else {
670 printk(KERN_INFO "radeon: switched off\n");
671 radeon_suspend_kms(dev, pmm);
672 /* don't suspend or resume card normally */
673 rdev->powered_down = true;
674 }
675}
676
677static bool radeon_switcheroo_can_switch(struct pci_dev *pdev)
678{
679 struct drm_device *dev = pci_get_drvdata(pdev);
680 bool can_switch;
681
682 spin_lock(&dev->count_lock);
683 can_switch = (dev->open_count == 0);
684 spin_unlock(&dev->count_lock);
685 return can_switch;
686}
687
688
658int radeon_device_init(struct radeon_device *rdev, 689int radeon_device_init(struct radeon_device *rdev,
659 struct drm_device *ddev, 690 struct drm_device *ddev,
660 struct pci_dev *pdev, 691 struct pci_dev *pdev,
@@ -737,6 +768,9 @@ int radeon_device_init(struct radeon_device *rdev,
737 /* this will fail for cards that aren't VGA class devices, just 768 /* this will fail for cards that aren't VGA class devices, just
738 * ignore it */ 769 * ignore it */
739 vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode); 770 vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode);
771 vga_switcheroo_register_client(rdev->pdev,
772 radeon_switcheroo_set_state,
773 radeon_switcheroo_can_switch);
740 774
741 r = radeon_init(rdev); 775 r = radeon_init(rdev);
742 if (r) 776 if (r)
@@ -768,6 +802,7 @@ void radeon_device_fini(struct radeon_device *rdev)
768 rdev->shutdown = true; 802 rdev->shutdown = true;
769 radeon_fini(rdev); 803 radeon_fini(rdev);
770 destroy_workqueue(rdev->wq); 804 destroy_workqueue(rdev->wq);
805 vga_switcheroo_unregister_client(rdev->pdev);
771 vga_client_register(rdev->pdev, NULL, NULL, NULL); 806 vga_client_register(rdev->pdev, NULL, NULL, NULL);
772 iounmap(rdev->rmmio); 807 iounmap(rdev->rmmio);
773 rdev->rmmio = NULL; 808 rdev->rmmio = NULL;
@@ -791,6 +826,8 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
791 } 826 }
792 rdev = dev->dev_private; 827 rdev = dev->dev_private;
793 828
829 if (rdev->powered_down)
830 return 0;
794 /* unpin the front buffers */ 831 /* unpin the front buffers */
795 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { 832 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
796 struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb); 833 struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb);
@@ -836,6 +873,9 @@ int radeon_resume_kms(struct drm_device *dev)
836{ 873{
837 struct radeon_device *rdev = dev->dev_private; 874 struct radeon_device *rdev = dev->dev_private;
838 875
876 if (rdev->powered_down)
877 return 0;
878
839 acquire_console_sem(); 879 acquire_console_sem();
840 pci_set_power_state(dev->pdev, PCI_D0); 880 pci_set_power_state(dev->pdev, PCI_D0);
841 pci_restore_state(dev->pdev); 881 pci_restore_state(dev->pdev);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index be99d4e55a34..f6456e02d1fe 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -343,6 +343,7 @@ static int __init radeon_init(void)
343 driver = &kms_driver; 343 driver = &kms_driver;
344 driver->driver_features |= DRIVER_MODESET; 344 driver->driver_features |= DRIVER_MODESET;
345 driver->num_ioctls = radeon_max_kms_ioctl; 345 driver->num_ioctls = radeon_max_kms_ioctl;
346 radeon_register_atpx_handler();
346 } 347 }
347 /* if the vga console setting is enabled still 348 /* if the vga console setting is enabled still
348 * let modprobe override it */ 349 * let modprobe override it */
@@ -352,6 +353,7 @@ static int __init radeon_init(void)
352static void __exit radeon_exit(void) 353static void __exit radeon_exit(void)
353{ 354{
354 drm_exit(driver); 355 drm_exit(driver);
356 radeon_unregister_atpx_handler();
355} 357}
356 358
357module_init(radeon_init); 359module_init(radeon_init);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h
index cf911859eac2..4fe16461bb1b 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.h
+++ b/drivers/gpu/drm/radeon/radeon_drv.h
@@ -462,6 +462,9 @@ extern void r600_blit_swap(struct drm_device *dev,
462 int sx, int sy, int dx, int dy, 462 int sx, int sy, int dx, int dy,
463 int w, int h, int src_pitch, int dst_pitch, int cpp); 463 int w, int h, int src_pitch, int dst_pitch, int cpp);
464 464
465/* atpx handler */
466void radeon_register_atpx_handler(void);
467void radeon_unregister_atpx_handler(void);
465/* Flags for stats.boxes 468/* Flags for stats.boxes
466 */ 469 */
467#define RADEON_BOX_DMA_IDLE 0x1 470#define RADEON_BOX_DMA_IDLE 0x1
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index cda112cc7a6c..8fccbf29235e 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -39,6 +39,8 @@
39 39
40#include "drm_fb_helper.h" 40#include "drm_fb_helper.h"
41 41
42#include <linux/vga_switcheroo.h>
43
42struct radeon_fb_device { 44struct radeon_fb_device {
43 struct drm_fb_helper helper; 45 struct drm_fb_helper helper;
44 struct radeon_framebuffer *rfb; 46 struct radeon_framebuffer *rfb;
@@ -286,6 +288,7 @@ int radeonfb_create(struct drm_device *dev,
286 rfbdev->rdev = rdev; 288 rfbdev->rdev = rdev;
287 289
288 mutex_unlock(&rdev->ddev->struct_mutex); 290 mutex_unlock(&rdev->ddev->struct_mutex);
291 vga_switcheroo_client_fb_set(rdev->ddev->pdev, info);
289 return 0; 292 return 0;
290 293
291out_unref: 294out_unref:
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 3c5002ea3f8f..20ec276e7596 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -30,6 +30,8 @@
30#include "radeon.h" 30#include "radeon.h"
31#include "radeon_drm.h" 31#include "radeon_drm.h"
32 32
33#include <linux/vga_switcheroo.h>
34
33int radeon_driver_unload_kms(struct drm_device *dev) 35int radeon_driver_unload_kms(struct drm_device *dev)
34{ 36{
35 struct radeon_device *rdev = dev->dev_private; 37 struct radeon_device *rdev = dev->dev_private;
@@ -136,6 +138,7 @@ int radeon_driver_firstopen_kms(struct drm_device *dev)
136 138
137void radeon_driver_lastclose_kms(struct drm_device *dev) 139void radeon_driver_lastclose_kms(struct drm_device *dev)
138{ 140{
141 vga_switcheroo_process_delayed_switch();
139} 142}
140 143
141int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) 144int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig
index 790e675b13eb..6116a0196214 100644
--- a/drivers/gpu/vga/Kconfig
+++ b/drivers/gpu/vga/Kconfig
@@ -8,3 +8,16 @@ config VGA_ARB
8 are accessed at same time they need some kind of coordination. Please 8 are accessed at same time they need some kind of coordination. Please
9 see Documentation/vgaarbiter.txt for more details. Select this to 9 see Documentation/vgaarbiter.txt for more details. Select this to
10 enable VGA arbiter. 10 enable VGA arbiter.
11
12config VGA_SWITCHEROO
13 bool "Laptop Hybrid Grapics - GPU switching support"
14 default y
15 depends on X86
16 depends on ACPI
17 help
18 Many laptops released in 2008/9/10 have two gpus with a multiplxer
19 to switch between them. This adds support for dynamic switching when
20 X isn't running and delayed switching until the next logoff. This
21 features is called hybrid graphics, ATI PowerXpress, and Nvidia
22 HybridPower.
23
diff --git a/drivers/gpu/vga/Makefile b/drivers/gpu/vga/Makefile
index 7cc8c1ed645b..14ca30b75d0a 100644
--- a/drivers/gpu/vga/Makefile
+++ b/drivers/gpu/vga/Makefile
@@ -1 +1,2 @@
1obj-$(CONFIG_VGA_ARB) += vgaarb.o 1obj-$(CONFIG_VGA_ARB) += vgaarb.o
2obj-$(CONFIG_VGA_SWITCHEROO) += vga_switcheroo.o
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
new file mode 100644
index 000000000000..a3f587a0aba9
--- /dev/null
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -0,0 +1,453 @@
1/*
2 * Copyright (c) 2010 Red Hat Inc.
3 * Author : Dave Airlie <airlied@redhat.com>
4 *
5 *
6 * Licensed under GPLv2
7 *
8 * vga_switcheroo.c - Support for laptop with dual GPU using one set of outputs
9
10 Switcher interface - methods require for ATPX and DCM
11 - switchto - this throws the output MUX switch
12 - discrete_set_power - sets the power state for the discrete card
13
14 GPU driver interface
15 - set_gpu_state - this should do the equiv of s/r for the card
16 - this should *not* set the discrete power state
17 - switch_check - check if the device is in a position to switch now
18 */
19
20#include <linux/module.h>
21#include <linux/dmi.h>
22#include <linux/seq_file.h>
23#include <linux/uaccess.h>
24#include <linux/fs.h>
25#include <linux/debugfs.h>
26#include <linux/fb.h>
27
28#include <acpi/acpi.h>
29#include <acpi/acpi_bus.h>
30
31#include <linux/pci.h>
32#include <linux/vga_switcheroo.h>
33
34struct vga_switcheroo_client {
35 struct pci_dev *pdev;
36 struct fb_info *fb_info;
37 int pwr_state;
38 void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state);
39 bool (*can_switch)(struct pci_dev *pdev);
40 int id;
41 bool active;
42};
43
44static DEFINE_MUTEX(vgasr_mutex);
45
46struct vgasr_priv {
47
48 bool active;
49 bool delayed_switch_active;
50 enum vga_switcheroo_client_id delayed_client_id;
51
52 struct dentry *debugfs_root;
53 struct dentry *switch_file;
54
55 int registered_clients;
56 struct vga_switcheroo_client clients[VGA_SWITCHEROO_MAX_CLIENTS];
57
58 struct vga_switcheroo_handler *handler;
59};
60
61static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv);
62static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
63
64/* only one switcheroo per system */
65static struct vgasr_priv vgasr_priv;
66
67int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
68{
69 mutex_lock(&vgasr_mutex);
70 if (vgasr_priv.handler) {
71 mutex_unlock(&vgasr_mutex);
72 return -EINVAL;
73 }
74
75 vgasr_priv.handler = handler;
76 mutex_unlock(&vgasr_mutex);
77 return 0;
78}
79EXPORT_SYMBOL(vga_switcheroo_register_handler);
80
81void vga_switcheroo_unregister_handler(void)
82{
83 mutex_lock(&vgasr_mutex);
84 vgasr_priv.handler = NULL;
85 mutex_unlock(&vgasr_mutex);
86}
87EXPORT_SYMBOL(vga_switcheroo_unregister_handler);
88
89static void vga_switcheroo_enable(void)
90{
91 int i;
92 int ret;
93 /* call the handler to init */
94 vgasr_priv.handler->init();
95
96 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
97 ret = vgasr_priv.handler->get_client_id(vgasr_priv.clients[i].pdev);
98 if (ret < 0)
99 return;
100
101 vgasr_priv.clients[i].id = ret;
102 }
103 vga_switcheroo_debugfs_init(&vgasr_priv);
104 vgasr_priv.active = true;
105}
106
107int vga_switcheroo_register_client(struct pci_dev *pdev,
108 void (*set_gpu_state)(struct pci_dev *pdev, enum vga_switcheroo_state),
109 bool (*can_switch)(struct pci_dev *pdev))
110{
111 int index;
112
113 mutex_lock(&vgasr_mutex);
114 /* don't do IGD vs DIS here */
115 if (vgasr_priv.registered_clients & 1)
116 index = 1;
117 else
118 index = 0;
119
120 vgasr_priv.clients[index].pwr_state = VGA_SWITCHEROO_ON;
121 vgasr_priv.clients[index].pdev = pdev;
122 vgasr_priv.clients[index].set_gpu_state = set_gpu_state;
123 vgasr_priv.clients[index].can_switch = can_switch;
124 vgasr_priv.clients[index].id = -1;
125 if (pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW)
126 vgasr_priv.clients[index].active = true;
127
128 vgasr_priv.registered_clients |= (1 << index);
129
130 /* if we get two clients + handler */
131 if (vgasr_priv.registered_clients == 0x3 && vgasr_priv.handler) {
132 printk(KERN_INFO "vga_switcheroo: enabled\n");
133 vga_switcheroo_enable();
134 }
135 mutex_unlock(&vgasr_mutex);
136 return 0;
137}
138EXPORT_SYMBOL(vga_switcheroo_register_client);
139
140void vga_switcheroo_unregister_client(struct pci_dev *pdev)
141{
142 int i;
143
144 mutex_lock(&vgasr_mutex);
145 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
146 if (vgasr_priv.clients[i].pdev == pdev) {
147 vgasr_priv.registered_clients &= ~(1 << i);
148 break;
149 }
150 }
151
152 printk(KERN_INFO "vga_switcheroo: disabled\n");
153 vga_switcheroo_debugfs_fini(&vgasr_priv);
154 vgasr_priv.active = false;
155 mutex_unlock(&vgasr_mutex);
156}
157EXPORT_SYMBOL(vga_switcheroo_unregister_client);
158
159void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
160 struct fb_info *info)
161{
162 int i;
163
164 mutex_lock(&vgasr_mutex);
165 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
166 if (vgasr_priv.clients[i].pdev == pdev) {
167 vgasr_priv.clients[i].fb_info = info;
168 break;
169 }
170 }
171 mutex_unlock(&vgasr_mutex);
172}
173EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
174
175static int vga_switcheroo_show(struct seq_file *m, void *v)
176{
177 int i;
178 mutex_lock(&vgasr_mutex);
179 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
180 seq_printf(m, "%d:%c:%s:%s\n", i,
181 vgasr_priv.clients[i].active ? '+' : ' ',
182 vgasr_priv.clients[i].pwr_state ? "Pwr" : "Off",
183 pci_name(vgasr_priv.clients[i].pdev));
184 }
185 mutex_unlock(&vgasr_mutex);
186 return 0;
187}
188
189static int vga_switcheroo_debugfs_open(struct inode *inode, struct file *file)
190{
191 return single_open(file, vga_switcheroo_show, NULL);
192}
193
194static int vga_switchon(struct vga_switcheroo_client *client)
195{
196 int ret;
197
198 ret = vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_ON);
199 /* call the driver callback to turn on device */
200 client->set_gpu_state(client->pdev, VGA_SWITCHEROO_ON);
201 client->pwr_state = VGA_SWITCHEROO_ON;
202 return 0;
203}
204
205static int vga_switchoff(struct vga_switcheroo_client *client)
206{
207 /* call the driver callback to turn off device */
208 client->set_gpu_state(client->pdev, VGA_SWITCHEROO_OFF);
209 vgasr_priv.handler->power_state(client->id, VGA_SWITCHEROO_OFF);
210 client->pwr_state = VGA_SWITCHEROO_OFF;
211 return 0;
212}
213
214static int vga_switchto(struct vga_switcheroo_client *new_client)
215{
216 int ret;
217 int i;
218 struct vga_switcheroo_client *active = NULL;
219
220 if (new_client->active == true)
221 return 0;
222
223 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
224 if (vgasr_priv.clients[i].active == true) {
225 active = &vgasr_priv.clients[i];
226 break;
227 }
228 }
229 if (!active)
230 return 0;
231
232 /* power up the first device */
233 ret = pci_enable_device(new_client->pdev);
234 if (ret)
235 return ret;
236
237 if (new_client->pwr_state == VGA_SWITCHEROO_OFF)
238 vga_switchon(new_client);
239
240 /* swap shadow resource to denote boot VGA device has changed so X starts on new device */
241 active->active = false;
242
243 active->pdev->resource[PCI_ROM_RESOURCE].flags &= ~IORESOURCE_ROM_SHADOW;
244 new_client->pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
245
246 if (new_client->fb_info) {
247 struct fb_event event;
248 event.info = new_client->fb_info;
249 fb_notifier_call_chain(FB_EVENT_REMAP_ALL_CONSOLE, &event);
250 }
251
252 ret = vgasr_priv.handler->switchto(new_client->id);
253 if (ret)
254 return ret;
255
256 if (active->pwr_state == VGA_SWITCHEROO_ON)
257 vga_switchoff(active);
258
259 new_client->active = true;
260 return 0;
261}
262
263static ssize_t
264vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
265 size_t cnt, loff_t *ppos)
266{
267 char usercmd[64];
268 const char *pdev_name;
269 int i, ret;
270 bool delay = false, can_switch;
271 int client_id = -1;
272 struct vga_switcheroo_client *client = NULL;
273
274 if (cnt > 63)
275 cnt = 63;
276
277 if (copy_from_user(usercmd, ubuf, cnt))
278 return -EFAULT;
279
280 mutex_lock(&vgasr_mutex);
281
282 if (!vgasr_priv.active)
283 return -EINVAL;
284
285 /* pwr off the device not in use */
286 if (strncmp(usercmd, "OFF", 3) == 0) {
287 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
288 if (vgasr_priv.clients[i].active)
289 continue;
290 if (vgasr_priv.clients[i].pwr_state == VGA_SWITCHEROO_ON)
291 vga_switchoff(&vgasr_priv.clients[i]);
292 }
293 goto out;
294 }
295 /* pwr on the device not in use */
296 if (strncmp(usercmd, "ON", 2) == 0) {
297 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
298 if (vgasr_priv.clients[i].active)
299 continue;
300 if (vgasr_priv.clients[i].pwr_state == VGA_SWITCHEROO_OFF)
301 vga_switchon(&vgasr_priv.clients[i]);
302 }
303 goto out;
304 }
305
306 /* request a delayed switch - test can we switch now */
307 if (strncmp(usercmd, "DIGD", 4) == 0) {
308 client_id = VGA_SWITCHEROO_IGD;
309 delay = true;
310 }
311
312 if (strncmp(usercmd, "DDIS", 4) == 0) {
313 client_id = VGA_SWITCHEROO_DIS;
314 delay = true;
315 }
316
317 if (strncmp(usercmd, "IGD", 3) == 0)
318 client_id = VGA_SWITCHEROO_IGD;
319
320 if (strncmp(usercmd, "DIS", 3) == 0)
321 client_id = VGA_SWITCHEROO_DIS;
322
323 if (client_id == -1)
324 goto out;
325
326 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
327 if (vgasr_priv.clients[i].id == client_id) {
328 client = &vgasr_priv.clients[i];
329 break;
330 }
331 }
332
333 vgasr_priv.delayed_switch_active = false;
334 /* okay we want a switch - test if devices are willing to switch */
335 can_switch = true;
336 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
337 can_switch = vgasr_priv.clients[i].can_switch(vgasr_priv.clients[i].pdev);
338 if (can_switch == false) {
339 printk(KERN_ERR "vga_switcheroo: client %d refused switch\n", i);
340 break;
341 }
342 }
343
344 if (can_switch == false && delay == false)
345 goto out;
346
347 if (can_switch == true) {
348 pdev_name = pci_name(client->pdev);
349 ret = vga_switchto(client);
350 if (ret)
351 printk(KERN_ERR "vga_switcheroo: switching failed %d\n", ret);
352 } else {
353 printk(KERN_INFO "vga_switcheroo: setting delayed switch to client %d\n", client->id);
354 vgasr_priv.delayed_switch_active = true;
355 vgasr_priv.delayed_client_id = client_id;
356
357 /* we should at least power up the card to
358 make the switch faster */
359 if (client->pwr_state == VGA_SWITCHEROO_OFF)
360 vga_switchon(client);
361 }
362
363out:
364 mutex_unlock(&vgasr_mutex);
365 return cnt;
366}
367
368static const struct file_operations vga_switcheroo_debugfs_fops = {
369 .owner = THIS_MODULE,
370 .open = vga_switcheroo_debugfs_open,
371 .write = vga_switcheroo_debugfs_write,
372 .read = seq_read,
373 .llseek = seq_lseek,
374 .release = single_release,
375};
376
377static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv)
378{
379 if (priv->switch_file) {
380 debugfs_remove(priv->switch_file);
381 priv->switch_file = NULL;
382 }
383 if (priv->debugfs_root) {
384 debugfs_remove(priv->debugfs_root);
385 priv->debugfs_root = NULL;
386 }
387}
388
389static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv)
390{
391 /* already initialised */
392 if (priv->debugfs_root)
393 return 0;
394 priv->debugfs_root = debugfs_create_dir("vgaswitcheroo", NULL);
395
396 if (!priv->debugfs_root) {
397 printk(KERN_ERR "vga_switcheroo: Cannot create /sys/kernel/debug/vgaswitcheroo\n");
398 goto fail;
399 }
400
401 priv->switch_file = debugfs_create_file("switch", 0644,
402 priv->debugfs_root, NULL, &vga_switcheroo_debugfs_fops);
403 if (!priv->switch_file) {
404 printk(KERN_ERR "vga_switcheroo: cannot create /sys/kernel/debug/vgaswitcheroo/switch\n");
405 goto fail;
406 }
407 return 0;
408fail:
409 vga_switcheroo_debugfs_fini(priv);
410 return -1;
411}
412
413int vga_switcheroo_process_delayed_switch(void)
414{
415 struct vga_switcheroo_client *client = NULL;
416 const char *pdev_name;
417 bool can_switch = true;
418 int i;
419 int ret;
420 int err = -EINVAL;
421
422 mutex_lock(&vgasr_mutex);
423 if (!vgasr_priv.delayed_switch_active)
424 goto err;
425
426 printk(KERN_INFO "vga_switcheroo: processing delayed switch to %d\n", vgasr_priv.delayed_client_id);
427
428 for (i = 0; i < VGA_SWITCHEROO_MAX_CLIENTS; i++) {
429 if (vgasr_priv.clients[i].id == vgasr_priv.delayed_client_id)
430 client = &vgasr_priv.clients[i];
431 can_switch = vgasr_priv.clients[i].can_switch(vgasr_priv.clients[i].pdev);
432 if (can_switch == false) {
433 printk(KERN_ERR "vga_switcheroo: client %d refused switch\n", i);
434 break;
435 }
436 }
437
438 if (can_switch == false || client == NULL)
439 goto err;
440
441 pdev_name = pci_name(client->pdev);
442 ret = vga_switchto(client);
443 if (ret)
444 printk(KERN_ERR "vga_switcheroo: delayed switching failed %d\n", ret);
445
446 vgasr_priv.delayed_switch_active = false;
447 err = 0;
448err:
449 mutex_unlock(&vgasr_mutex);
450 return err;
451}
452EXPORT_SYMBOL(vga_switcheroo_process_delayed_switch);
453