aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2011-05-08 23:23:18 -0400
committerDave Airlie <airlied@redhat.com>2011-05-08 23:23:18 -0400
commit269dc2d9194f74b920647e0f2ed0d822dc431770 (patch)
tree6b6be1a7b9c152e27f12fba9d9d75cced9551b21
parent776f2b7cb473baa52cdeee9804073342dee7d7cb (diff)
parent000703f44c77b152cd966eaf06f4ab043274ff46 (diff)
Merge remote branch 'korg/drm-nvidia-switch-fixes' into drm-core-next
* korg/drm-nvidia-switch-fixes: mxm/wmi: add MXMX interface entry point. nouveau: add optimus detection to DSM code. vgaarb: use bridges to control VGA routing where possible. nouveau/acpi: hook up to the MXM method for mux switching. platform/x86: add MXM WMI driver.
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c108
-rw-r--r--drivers/gpu/vga/vgaarb.c113
-rw-r--r--drivers/pci/pci.c25
-rw-r--r--drivers/platform/x86/Kconfig7
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/mxm-wmi.c111
-rw-r--r--include/linux/mxm-wmi.h33
-rw-r--r--include/linux/pci.h7
9 files changed, 368 insertions, 38 deletions
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index de70959b9ed5..e2f8a38d5f24 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -11,6 +11,7 @@ config DRM_NOUVEAU
11 select FRAMEBUFFER_CONSOLE if !EXPERT 11 select FRAMEBUFFER_CONSOLE if !EXPERT
12 select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT 12 select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
13 select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT 13 select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
14 select MXM_WMI if ACPI
14 help 15 help
15 Choose this option for open-source nVidia support. 16 Choose this option for open-source nVidia support.
16 17
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index a54238058dc5..f0d459bb46e4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -4,6 +4,8 @@
4#include <acpi/acpi_drivers.h> 4#include <acpi/acpi_drivers.h>
5#include <acpi/acpi_bus.h> 5#include <acpi/acpi_bus.h>
6#include <acpi/video.h> 6#include <acpi/video.h>
7#include <acpi/acpi.h>
8#include <linux/mxm-wmi.h>
7 9
8#include "drmP.h" 10#include "drmP.h"
9#include "drm.h" 11#include "drm.h"
@@ -35,15 +37,71 @@
35 37
36static struct nouveau_dsm_priv { 38static struct nouveau_dsm_priv {
37 bool dsm_detected; 39 bool dsm_detected;
40 bool optimus_detected;
38 acpi_handle dhandle; 41 acpi_handle dhandle;
39 acpi_handle rom_handle; 42 acpi_handle rom_handle;
40} nouveau_dsm_priv; 43} nouveau_dsm_priv;
41 44
45#define NOUVEAU_DSM_HAS_MUX 0x1
46#define NOUVEAU_DSM_HAS_OPT 0x2
47
42static const char nouveau_dsm_muid[] = { 48static const char nouveau_dsm_muid[] = {
43 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D, 49 0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
44 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4, 50 0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
45}; 51};
46 52
53static const char nouveau_op_dsm_muid[] = {
54 0xF8, 0xD8, 0x86, 0xA4, 0xDA, 0x0B, 0x1B, 0x47,
55 0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0,
56};
57
58static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
59{
60 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
61 struct acpi_object_list input;
62 union acpi_object params[4];
63 union acpi_object *obj;
64 int err;
65
66 input.count = 4;
67 input.pointer = params;
68 params[0].type = ACPI_TYPE_BUFFER;
69 params[0].buffer.length = sizeof(nouveau_op_dsm_muid);
70 params[0].buffer.pointer = (char *)nouveau_op_dsm_muid;
71 params[1].type = ACPI_TYPE_INTEGER;
72 params[1].integer.value = 0x00000100;
73 params[2].type = ACPI_TYPE_INTEGER;
74 params[2].integer.value = func;
75 params[3].type = ACPI_TYPE_BUFFER;
76 params[3].buffer.length = 0;
77
78 err = acpi_evaluate_object(handle, "_DSM", &input, &output);
79 if (err) {
80 printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
81 return err;
82 }
83
84 obj = (union acpi_object *)output.pointer;
85
86 if (obj->type == ACPI_TYPE_INTEGER)
87 if (obj->integer.value == 0x80000002) {
88 return -ENODEV;
89 }
90
91 if (obj->type == ACPI_TYPE_BUFFER) {
92 if (obj->buffer.length == 4 && result) {
93 *result = 0;
94 *result |= obj->buffer.pointer[0];
95 *result |= (obj->buffer.pointer[1] << 8);
96 *result |= (obj->buffer.pointer[2] << 16);
97 *result |= (obj->buffer.pointer[3] << 24);
98 }
99 }
100
101 kfree(output.pointer);
102 return 0;
103}
104
47static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result) 105static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
48{ 106{
49 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 107 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -92,6 +150,8 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
92 150
93static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id) 151static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
94{ 152{
153 mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
154 mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
95 return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL); 155 return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL);
96} 156}
97 157
@@ -148,11 +208,11 @@ static struct vga_switcheroo_handler nouveau_dsm_handler = {
148 .get_client_id = nouveau_dsm_get_client_id, 208 .get_client_id = nouveau_dsm_get_client_id,
149}; 209};
150 210
151static bool nouveau_dsm_pci_probe(struct pci_dev *pdev) 211static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
152{ 212{
153 acpi_handle dhandle, nvidia_handle; 213 acpi_handle dhandle, nvidia_handle;
154 acpi_status status; 214 acpi_status status;
155 int ret; 215 int ret, retval = 0;
156 uint32_t result; 216 uint32_t result;
157 217
158 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); 218 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
@@ -166,11 +226,17 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
166 226
167 ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED, 227 ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED,
168 NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result); 228 NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
169 if (ret < 0) 229 if (ret == 0)
170 return false; 230 retval |= NOUVEAU_DSM_HAS_MUX;
171 231
172 nouveau_dsm_priv.dhandle = dhandle; 232 ret = nouveau_optimus_dsm(dhandle, 0, 0, &result);
173 return true; 233 if (ret == 0)
234 retval |= NOUVEAU_DSM_HAS_OPT;
235
236 if (retval)
237 nouveau_dsm_priv.dhandle = dhandle;
238
239 return retval;
174} 240}
175 241
176static bool nouveau_dsm_detect(void) 242static bool nouveau_dsm_detect(void)
@@ -179,22 +245,42 @@ static bool nouveau_dsm_detect(void)
179 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name}; 245 struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
180 struct pci_dev *pdev = NULL; 246 struct pci_dev *pdev = NULL;
181 int has_dsm = 0; 247 int has_dsm = 0;
248 int has_optimus;
182 int vga_count = 0; 249 int vga_count = 0;
250 bool guid_valid;
251 int retval;
252 bool ret = false;
253
254 /* lookup the MXM GUID */
255 guid_valid = mxm_wmi_supported();
183 256
257 if (guid_valid)
258 printk("MXM: GUID detected in BIOS\n");
259
260 /* now do DSM detection */
184 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) { 261 while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
185 vga_count++; 262 vga_count++;
186 263
187 has_dsm |= (nouveau_dsm_pci_probe(pdev) == true); 264 retval = nouveau_dsm_pci_probe(pdev);
265 printk("ret val is %d\n", retval);
266 if (retval & NOUVEAU_DSM_HAS_MUX)
267 has_dsm |= 1;
268 if (retval & NOUVEAU_DSM_HAS_OPT)
269 has_optimus = 1;
188 } 270 }
189 271
190 if (vga_count == 2 && has_dsm) { 272 if (vga_count == 2 && has_dsm && guid_valid) {
191 acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer); 273 acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
192 printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", 274 printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
193 acpi_method_name); 275 acpi_method_name);
194 nouveau_dsm_priv.dsm_detected = true; 276 nouveau_dsm_priv.dsm_detected = true;
195 return true; 277 ret = true;
196 } 278 }
197 return false; 279
280 if (has_optimus == 1)
281 nouveau_dsm_priv.optimus_detected = true;
282
283 return ret;
198} 284}
199 285
200void nouveau_register_dsm_handler(void) 286void nouveau_register_dsm_handler(void)
@@ -247,7 +333,7 @@ bool nouveau_acpi_rom_supported(struct pci_dev *pdev)
247 acpi_status status; 333 acpi_status status;
248 acpi_handle dhandle, rom_handle; 334 acpi_handle dhandle, rom_handle;
249 335
250 if (!nouveau_dsm_priv.dsm_detected) 336 if (!nouveau_dsm_priv.dsm_detected && !nouveau_dsm_priv.optimus_detected)
251 return false; 337 return false;
252 338
253 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev); 339 dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index be8d4cb5861c..8a1021f2e319 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -61,7 +61,7 @@ struct vga_device {
61 unsigned int mem_lock_cnt; /* legacy MEM lock count */ 61 unsigned int mem_lock_cnt; /* legacy MEM lock count */
62 unsigned int io_norm_cnt; /* normal IO count */ 62 unsigned int io_norm_cnt; /* normal IO count */
63 unsigned int mem_norm_cnt; /* normal MEM count */ 63 unsigned int mem_norm_cnt; /* normal MEM count */
64 64 bool bridge_has_one_vga;
65 /* allow IRQ enable/disable hook */ 65 /* allow IRQ enable/disable hook */
66 void *cookie; 66 void *cookie;
67 void (*irq_set_state)(void *cookie, bool enable); 67 void (*irq_set_state)(void *cookie, bool enable);
@@ -165,6 +165,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
165 unsigned int wants, legacy_wants, match; 165 unsigned int wants, legacy_wants, match;
166 struct vga_device *conflict; 166 struct vga_device *conflict;
167 unsigned int pci_bits; 167 unsigned int pci_bits;
168 u32 flags = 0;
169
168 /* Account for "normal" resources to lock. If we decode the legacy, 170 /* Account for "normal" resources to lock. If we decode the legacy,
169 * counterpart, we need to request it as well 171 * counterpart, we need to request it as well
170 */ 172 */
@@ -237,16 +239,23 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
237 /* looks like he doesn't have a lock, we can steal 239 /* looks like he doesn't have a lock, we can steal
238 * them from him 240 * them from him
239 */ 241 */
240 vga_irq_set_state(conflict, false);
241 242
243 flags = 0;
242 pci_bits = 0; 244 pci_bits = 0;
243 if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
244 pci_bits |= PCI_COMMAND_MEMORY;
245 if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
246 pci_bits |= PCI_COMMAND_IO;
247 245
248 pci_set_vga_state(conflict->pdev, false, pci_bits, 246 if (!conflict->bridge_has_one_vga) {
249 change_bridge); 247 vga_irq_set_state(conflict, false);
248 flags |= PCI_VGA_STATE_CHANGE_DECODES;
249 if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
250 pci_bits |= PCI_COMMAND_MEMORY;
251 if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
252 pci_bits |= PCI_COMMAND_IO;
253 }
254
255 if (change_bridge)
256 flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
257
258 pci_set_vga_state(conflict->pdev, false, pci_bits, flags);
250 conflict->owns &= ~lwants; 259 conflict->owns &= ~lwants;
251 /* If he also owned non-legacy, that is no longer the case */ 260 /* If he also owned non-legacy, that is no longer the case */
252 if (lwants & VGA_RSRC_LEGACY_MEM) 261 if (lwants & VGA_RSRC_LEGACY_MEM)
@@ -261,14 +270,24 @@ enable_them:
261 * also have in "decodes". We can lock resources we don't decode but 270 * also have in "decodes". We can lock resources we don't decode but
262 * not own them. 271 * not own them.
263 */ 272 */
273 flags = 0;
264 pci_bits = 0; 274 pci_bits = 0;
265 if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
266 pci_bits |= PCI_COMMAND_MEMORY;
267 if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
268 pci_bits |= PCI_COMMAND_IO;
269 pci_set_vga_state(vgadev->pdev, true, pci_bits, !!(wants & VGA_RSRC_LEGACY_MASK));
270 275
271 vga_irq_set_state(vgadev, true); 276 if (!vgadev->bridge_has_one_vga) {
277 flags |= PCI_VGA_STATE_CHANGE_DECODES;
278 if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
279 pci_bits |= PCI_COMMAND_MEMORY;
280 if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
281 pci_bits |= PCI_COMMAND_IO;
282 }
283 if (!!(wants & VGA_RSRC_LEGACY_MASK))
284 flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
285
286 pci_set_vga_state(vgadev->pdev, true, pci_bits, flags);
287
288 if (!vgadev->bridge_has_one_vga) {
289 vga_irq_set_state(vgadev, true);
290 }
272 vgadev->owns |= (wants & vgadev->decodes); 291 vgadev->owns |= (wants & vgadev->decodes);
273lock_them: 292lock_them:
274 vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK); 293 vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK);
@@ -421,6 +440,62 @@ bail:
421} 440}
422EXPORT_SYMBOL(vga_put); 441EXPORT_SYMBOL(vga_put);
423 442
443/* Rules for using a bridge to control a VGA descendant decoding:
444 if a bridge has only one VGA descendant then it can be used
445 to control the VGA routing for that device.
446 It should always use the bridge closest to the device to control it.
447 If a bridge has a direct VGA descendant, but also have a sub-bridge
448 VGA descendant then we cannot use that bridge to control the direct VGA descendant.
449 So for every device we register, we need to iterate all its parent bridges
450 so we can invalidate any devices using them properly.
451*/
452static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev)
453{
454 struct vga_device *same_bridge_vgadev;
455 struct pci_bus *new_bus, *bus;
456 struct pci_dev *new_bridge, *bridge;
457
458 vgadev->bridge_has_one_vga = true;
459
460 if (list_empty(&vga_list))
461 return;
462
463 /* okay iterate the new devices bridge hierarachy */
464 new_bus = vgadev->pdev->bus;
465 while (new_bus) {
466 new_bridge = new_bus->self;
467
468 if (new_bridge) {
469 /* go through list of devices already registered */
470 list_for_each_entry(same_bridge_vgadev, &vga_list, list) {
471 bus = same_bridge_vgadev->pdev->bus;
472 bridge = bus->self;
473
474 /* see if the share a bridge with this device */
475 if (new_bridge == bridge) {
476 /* if their direct parent bridge is the same
477 as any bridge of this device then it can't be used
478 for that device */
479 same_bridge_vgadev->bridge_has_one_vga = false;
480 }
481
482 /* now iterate the previous devices bridge hierarchy */
483 /* if the new devices parent bridge is in the other devices
484 hierarchy then we can't use it to control this device */
485 while (bus) {
486 bridge = bus->self;
487 if (bridge) {
488 if (bridge == vgadev->pdev->bus->self)
489 vgadev->bridge_has_one_vga = false;
490 }
491 bus = bus->parent;
492 }
493 }
494 }
495 new_bus = new_bus->parent;
496 }
497}
498
424/* 499/*
425 * Currently, we assume that the "initial" setup of the system is 500 * Currently, we assume that the "initial" setup of the system is
426 * not sane, that is we come up with conflicting devices and let 501 * not sane, that is we come up with conflicting devices and let
@@ -500,6 +575,8 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
500 vga_default = pci_dev_get(pdev); 575 vga_default = pci_dev_get(pdev);
501#endif 576#endif
502 577
578 vga_arbiter_check_bridge_sharing(vgadev);
579
503 /* Add to the list */ 580 /* Add to the list */
504 list_add(&vgadev->list, &vga_list); 581 list_add(&vgadev->list, &vga_list);
505 vga_count++; 582 vga_count++;
@@ -1222,6 +1299,7 @@ static int __init vga_arb_device_init(void)
1222{ 1299{
1223 int rc; 1300 int rc;
1224 struct pci_dev *pdev; 1301 struct pci_dev *pdev;
1302 struct vga_device *vgadev;
1225 1303
1226 rc = misc_register(&vga_arb_device); 1304 rc = misc_register(&vga_arb_device);
1227 if (rc < 0) 1305 if (rc < 0)
@@ -1238,6 +1316,13 @@ static int __init vga_arb_device_init(void)
1238 vga_arbiter_add_pci_device(pdev); 1316 vga_arbiter_add_pci_device(pdev);
1239 1317
1240 pr_info("vgaarb: loaded\n"); 1318 pr_info("vgaarb: loaded\n");
1319
1320 list_for_each_entry(vgadev, &vga_list, list) {
1321 if (vgadev->bridge_has_one_vga)
1322 pr_info("vgaarb: bridge control possible %s\n", pci_name(vgadev->pdev));
1323 else
1324 pr_info("vgaarb: no bridge control possible %s\n", pci_name(vgadev->pdev));
1325 }
1241 return rc; 1326 return rc;
1242} 1327}
1243subsys_initcall(vga_arb_device_init); 1328subsys_initcall(vga_arb_device_init);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2472e7177b4b..a339237f4f96 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2875,31 +2875,34 @@ static int pci_set_vga_state_arch(struct pci_dev *dev, bool decode,
2875 * @dev: the PCI device 2875 * @dev: the PCI device
2876 * @decode: true = enable decoding, false = disable decoding 2876 * @decode: true = enable decoding, false = disable decoding
2877 * @command_bits: PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY 2877 * @command_bits: PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY
2878 * @change_bridge: traverse ancestors and change bridges 2878 * @change_bridge_flags: traverse ancestors and change bridges
2879 * CHANGE_BRIDGE_ONLY / CHANGE_BRIDGE
2879 */ 2880 */
2880int pci_set_vga_state(struct pci_dev *dev, bool decode, 2881int pci_set_vga_state(struct pci_dev *dev, bool decode,
2881 unsigned int command_bits, bool change_bridge) 2882 unsigned int command_bits, u32 flags)
2882{ 2883{
2883 struct pci_bus *bus; 2884 struct pci_bus *bus;
2884 struct pci_dev *bridge; 2885 struct pci_dev *bridge;
2885 u16 cmd; 2886 u16 cmd;
2886 int rc; 2887 int rc;
2887 2888
2888 WARN_ON(command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)); 2889 WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) & (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)));
2889 2890
2890 /* ARCH specific VGA enables */ 2891 /* ARCH specific VGA enables */
2891 rc = pci_set_vga_state_arch(dev, decode, command_bits, change_bridge); 2892 rc = pci_set_vga_state_arch(dev, decode, command_bits, flags);
2892 if (rc) 2893 if (rc)
2893 return rc; 2894 return rc;
2894 2895
2895 pci_read_config_word(dev, PCI_COMMAND, &cmd); 2896 if (flags & PCI_VGA_STATE_CHANGE_DECODES) {
2896 if (decode == true) 2897 pci_read_config_word(dev, PCI_COMMAND, &cmd);
2897 cmd |= command_bits; 2898 if (decode == true)
2898 else 2899 cmd |= command_bits;
2899 cmd &= ~command_bits; 2900 else
2900 pci_write_config_word(dev, PCI_COMMAND, cmd); 2901 cmd &= ~command_bits;
2902 pci_write_config_word(dev, PCI_COMMAND, cmd);
2903 }
2901 2904
2902 if (change_bridge == false) 2905 if (!(flags & PCI_VGA_STATE_CHANGE_BRIDGE))
2903 return 0; 2906 return 0;
2904 2907
2905 bus = dev->bus; 2908 bus = dev->bus;
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 0485e394712a..94914572dd7f 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -753,4 +753,11 @@ config SAMSUNG_LAPTOP
753 To compile this driver as a module, choose M here: the module 753 To compile this driver as a module, choose M here: the module
754 will be called samsung-laptop. 754 will be called samsung-laptop.
755 755
756config MXM_WMI
757 tristate "WMI support for MXM Laptop Graphics"
758 depends on WMI
759 ---help---
760 MXM is a standard for laptop graphics cards, the WMI interface
761 is required for switchable nvidia graphics machines
762
756endif # X86_PLATFORM_DEVICES 763endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 029e8861d086..a7ab3bc7b3a1 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -42,3 +42,4 @@ obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o
42obj-$(CONFIG_IBM_RTL) += ibm_rtl.o 42obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
43obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o 43obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o
44obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o 44obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
45obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
diff --git a/drivers/platform/x86/mxm-wmi.c b/drivers/platform/x86/mxm-wmi.c
new file mode 100644
index 000000000000..0aea63b3729a
--- /dev/null
+++ b/drivers/platform/x86/mxm-wmi.c
@@ -0,0 +1,111 @@
1/*
2 * MXM WMI driver
3 *
4 * Copyright(C) 2010 Red Hat.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <linux/kernel.h>
21#include <linux/module.h>
22#include <linux/init.h>
23#include <acpi/acpi_bus.h>
24#include <acpi/acpi_drivers.h>
25
26MODULE_AUTHOR("Dave Airlie");
27MODULE_DESCRIPTION("MXM WMI Driver");
28MODULE_LICENSE("GPL");
29
30#define MXM_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
31
32MODULE_ALIAS("wmi:"MXM_WMMX_GUID);
33
34#define MXM_WMMX_FUNC_MXDS 0x5344584D /* "MXDS" */
35#define MXM_WMMX_FUNC_MXMX 0x53445344 /* "MXMX" */
36
37struct mxds_args {
38 u32 func;
39 u32 args;
40 u32 xarg;
41};
42
43int mxm_wmi_call_mxds(int adapter)
44{
45 struct mxds_args args = {
46 .func = MXM_WMMX_FUNC_MXDS,
47 .args = 0,
48 .xarg = 1,
49 };
50 struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
51 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
52 acpi_status status;
53
54 printk("calling mux switch %d\n", adapter);
55
56 status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input,
57 &output);
58
59 if (ACPI_FAILURE(status))
60 return status;
61
62 printk("mux switched %d\n", status);
63 return 0;
64
65}
66EXPORT_SYMBOL_GPL(mxm_wmi_call_mxds);
67
68int mxm_wmi_call_mxmx(int adapter)
69{
70 struct mxds_args args = {
71 .func = MXM_WMMX_FUNC_MXMX,
72 .args = 0,
73 .xarg = 1,
74 };
75 struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
76 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
77 acpi_status status;
78
79 printk("calling mux switch %d\n", adapter);
80
81 status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input,
82 &output);
83
84 if (ACPI_FAILURE(status))
85 return status;
86
87 printk("mux mutex set switched %d\n", status);
88 return 0;
89
90}
91EXPORT_SYMBOL_GPL(mxm_wmi_call_mxmx);
92
93bool mxm_wmi_supported(void)
94{
95 bool guid_valid;
96 guid_valid = wmi_has_guid(MXM_WMMX_GUID);
97 return guid_valid;
98}
99EXPORT_SYMBOL_GPL(mxm_wmi_supported);
100
101static int __init mxm_wmi_init(void)
102{
103 return 0;
104}
105
106static void __exit mxm_wmi_exit(void)
107{
108}
109
110module_init(mxm_wmi_init);
111module_exit(mxm_wmi_exit);
diff --git a/include/linux/mxm-wmi.h b/include/linux/mxm-wmi.h
new file mode 100644
index 000000000000..617a2950523c
--- /dev/null
+++ b/include/linux/mxm-wmi.h
@@ -0,0 +1,33 @@
1/*
2 * MXM WMI driver
3 *
4 * Copyright(C) 2010 Red Hat.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#ifndef MXM_WMI_H
22#define MXM_WMI_H
23
24/* discrete adapters */
25#define MXM_MXDS_ADAPTER_0 0x0
26#define MXM_MXDS_ADAPTER_1 0x0
27/* integrated adapter */
28#define MXM_MXDS_ADAPTER_IGD 0x10
29int mxm_wmi_call_mxds(int adapter);
30int mxm_wmi_call_mxmx(int adapter);
31bool mxm_wmi_supported(void);
32
33#endif
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 96f70d7e058d..f2e57b2e6a81 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -915,8 +915,11 @@ int pci_cfg_space_size_ext(struct pci_dev *dev);
915int pci_cfg_space_size(struct pci_dev *dev); 915int pci_cfg_space_size(struct pci_dev *dev);
916unsigned char pci_bus_max_busnr(struct pci_bus *bus); 916unsigned char pci_bus_max_busnr(struct pci_bus *bus);
917 917
918#define PCI_VGA_STATE_CHANGE_BRIDGE (1 << 0)
919#define PCI_VGA_STATE_CHANGE_DECODES (1 << 1)
920
918int pci_set_vga_state(struct pci_dev *pdev, bool decode, 921int pci_set_vga_state(struct pci_dev *pdev, bool decode,
919 unsigned int command_bits, bool change_bridge); 922 unsigned int command_bits, u32 flags);
920/* kmem_cache style wrapper around pci_alloc_consistent() */ 923/* kmem_cache style wrapper around pci_alloc_consistent() */
921 924
922#include <linux/pci-dma.h> 925#include <linux/pci-dma.h>
@@ -1061,7 +1064,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
1061 1064
1062/* some architectures require additional setup to direct VGA traffic */ 1065/* some architectures require additional setup to direct VGA traffic */
1063typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode, 1066typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode,
1064 unsigned int command_bits, bool change_bridge); 1067 unsigned int command_bits, u32 flags);
1065extern void pci_register_set_vga_state(arch_set_vga_state_t func); 1068extern void pci_register_set_vga_state(arch_set_vga_state_t func);
1066 1069
1067#else /* CONFIG_PCI is not enabled */ 1070#else /* CONFIG_PCI is not enabled */