All of lore.kernel.org
 help / color / mirror / Atom feed
* properly check for _DSM function support and Optimus support for vga_switcheroo
@ 2011-12-17 12:14 Lekensteyn
       [not found] ` <CALBR5ZxR9iuvT57bDZ8yW9ZkZjuoUhBTYw4HBsmsiwoRi4gSkw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
  0 siblings, 1 reply; 9+ messages in thread
From: Lekensteyn @ 2011-12-17 12:14 UTC (permalink / raw)
  To: nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW


[-- Attachment #1.1: Type: text/plain, Size: 892 bytes --]

Hello guys,

I've prepared a patch based on my findings for the bbswitch module
(https://github.com/Lekensteyn/acpi-stuff/tree/master/bbswitch). This adds
a proper
check whether a _DSM function is supported or not and make OFF / ON for
vga_switcheroo work for nVidia Optimus models. The patch is based against
the
mainline kernel.

It has been tested on my Clevo B7130 laptop running kernel 3.2 which has a
GT425M
dGPU:
# cat /sys/kernel/debug/vgaswitcheroo/switch
0:IGD:+:Pwr:0000:00:02.0
1:DIS: :Pwr:0000:01:00.0
# tee /sys/kernel/debug/vgaswitcheroo/switch <<<OFF
OFF
# cat /sys/kernel/debug/vgaswitcheroo/switch
0:IGD:+:Pwr:0000:00:02.0
1:DIS: :Off:0000:01:00.0
# tee /sys/kernel/debug/vgaswitcheroo/switch <<<ON
ON
# cat /sys/kernel/debug/vgaswitcheroo/switch
0:IGD:+:Pwr:0000:00:02.0
1:DIS: :Pwr:0000:01:00.0

The iGPU/dGPU LEDS on the keyboard also change as a result.

Regards,
Peter

[-- Attachment #1.2: Type: text/html, Size: 1084 bytes --]

[-- Attachment #2: nouveau-switcheroo-optimus.patch --]
[-- Type: text/x-diff, Size: 8640 bytes --]

From b6e1b5b316ae17ccb7def0a8b38e69ad4c99c55d Mon Sep 17 00:00:00 2001
From: Peter Lekensteyn <lekensteyn@gmail.com>
Date: Sat, 17 Dec 2011 12:53:43 +0100
Subject: [PATCH 1/2] nouveau: properly check for _DSM function support

According to the ACPI spec version 4, section 9.14.1, _DSM functions
must return a value with the first bit enabled if any DSM functions are
supported for the given UUID and revision ID. For a given function index n
to be marked supported, bit n must be enabled.

Signed-off-by: Peter Lekensteyn <lekensteyn@gmail.com>
---
 drivers/gpu/drm/nouveau/nouveau_acpi.c |   35 ++++++++++++++++++++-----------
 1 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 525744d..96756d0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -18,12 +18,6 @@
 
 #include <linux/vga_switcheroo.h>
 
-#define NOUVEAU_DSM_SUPPORTED 0x00
-#define NOUVEAU_DSM_SUPPORTED_FUNCTIONS 0x00
-
-#define NOUVEAU_DSM_ACTIVE 0x01
-#define NOUVEAU_DSM_ACTIVE_QUERY 0x00
-
 #define NOUVEAU_DSM_LED 0x02
 #define NOUVEAU_DSM_LED_STATE 0x00
 #define NOUVEAU_DSM_LED_OFF 0x10
@@ -35,6 +29,7 @@
 #define NOUVEAU_DSM_POWER_SPEED 0x01
 #define NOUVEAU_DSM_POWER_STAMINA 0x02
 
+#define NOUVEAU_DSM_OPTIMUS_FN 0x1A
 static struct nouveau_dsm_priv {
 	bool dsm_detected;
 	bool optimus_detected;
@@ -148,6 +143,23 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
 	return 0;
 }
 
+/* Returns 1 if a DSM function is usable and 0 otherwise */
+static int nouveau_test_dsm(acpi_handle test_handle,
+	int (*dsm_func)(acpi_handle, int, int, uint32_t *),
+	int sfnc)
+{
+	u32 result = 0;
+
+	/* Function 0 returns a Buffer containing available functions. The args
+	 * parameter is ignored for function 0, so just put 0 in it */
+	if (dsm_func(test_handle, 0, 0, &result))
+		return 0;
+
+	/* ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. If
+	 * the n-th bit is enabled, function n is supported */
+	return result & 1 && result & (1 << sfnc);
+}
+
 static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
 {
 	mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
@@ -212,8 +224,7 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
 {
 	acpi_handle dhandle, nvidia_handle;
 	acpi_status status;
-	int ret, retval = 0;
-	uint32_t result;
+	int retval = 0;
 
 	dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
 	if (!dhandle)
@@ -224,13 +235,11 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
 		return false;
 	}
 
-	ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED,
-			  NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
-	if (ret == 0)
+	if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER))
 		retval |= NOUVEAU_DSM_HAS_MUX;
 
-	ret = nouveau_optimus_dsm(dhandle, 0, 0, &result);
-	if (ret == 0)
+	if (nouveau_test_dsm(dhandle, nouveau_optimus_dsm,
+		NOUVEAU_DSM_OPTIMUS_FN))
 		retval |= NOUVEAU_DSM_HAS_OPT;
 
 	if (retval)
-- 
1.7.5.4


From 58c5de8578e387ce0dbd8a77f9cbc36b2f5823a1 Mon Sep 17 00:00:00 2001
From: Peter Lekensteyn <lekensteyn@gmail.com>
Date: Sat, 17 Dec 2011 12:54:04 +0100
Subject: [PATCH 2/2] nouveau: Support Optimus models for vga_switcheroo

Newer nVidia cards with Optimus do not support/use the DSM switching functions.
Instead, it require a DSM function to be called prior to bringing a device into
D3 state. No other _DSM calls are necessary before/after enabling/disabling a
device. Switching between discrete and integrated GPU is not supported by
this Optimus _DSM call, therefore return on the switching method.

Signed-off-by: Peter Lekensteyn <lekensteyn@gmail.com>
---
 drivers/gpu/drm/nouveau/nouveau_acpi.c  |   44 +++++++++++++++++++++++++++---
 drivers/gpu/drm/nouveau/nouveau_drv.h   |    1 +
 drivers/gpu/drm/nouveau/nouveau_state.c |    1 +
 3 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 96756d0..7814a76 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -30,6 +30,8 @@
 #define NOUVEAU_DSM_POWER_STAMINA 0x02
 
 #define NOUVEAU_DSM_OPTIMUS_FN 0x1A
+#define NOUVEAU_DSM_OPTIMUS_ARGS 0x03000001
+
 static struct nouveau_dsm_priv {
 	bool dsm_detected;
 	bool optimus_detected;
@@ -56,7 +58,8 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
 	struct acpi_object_list input;
 	union acpi_object params[4];
 	union acpi_object *obj;
-	int err;
+	int i, err;
+	char args_buff[4];
 
 	input.count = 4;
 	input.pointer = params;
@@ -68,7 +71,11 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *
 	params[2].type = ACPI_TYPE_INTEGER;
 	params[2].integer.value = func;
 	params[3].type = ACPI_TYPE_BUFFER;
-	params[3].buffer.length = 0;
+	params[3].buffer.length = 4;
+	/* ACPI is little endian, AABBCCDD becomes {DD,CC,BB,AA} */
+	for (i = 0; i < 4; i++)
+		args_buff[i] = (arg >> i * 8) & 0xFF;
+	params[3].buffer.pointer = args_buff;
 
 	err = acpi_evaluate_object(handle, "_DSM", &input, &output);
 	if (err) {
@@ -180,6 +187,10 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero
 
 static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
 {
+	/* perhaps the _DSM functions are mutually exclusive, but prepare for
+	 * the future */
+	if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected)
+		return 0;
 	if (id == VGA_SWITCHEROO_IGD)
 		return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA);
 	else
@@ -192,6 +203,11 @@ static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
 	if (id == VGA_SWITCHEROO_IGD)
 		return 0;
 
+	/* Optimus laptops have the card already disabled in
+	 * nouveau_switcheroo_set_state */
+	if (!nouveau_dsm_priv.dsm_detected && nouveau_dsm_priv.optimus_detected)
+		return 0;
+
 	return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
 }
 
@@ -278,15 +294,22 @@ static bool nouveau_dsm_detect(void)
 	}
 
 	if (vga_count == 2 && has_dsm && guid_valid) {
-		acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
+		acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
+			&buffer);
 		printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
-		       acpi_method_name);
+			acpi_method_name);
 		nouveau_dsm_priv.dsm_detected = true;
 		ret = true;
 	}
 
-	if (has_optimus == 1)
+	if (has_optimus == 1) {
+		acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME,
+			&buffer);
+		printk(KERN_INFO "VGA switcheroo: detected Optimus DSM method %s handle\n",
+			acpi_method_name);
 		nouveau_dsm_priv.optimus_detected = true;
+		ret = true;
+	}
 
 	return ret;
 }
@@ -302,6 +325,17 @@ void nouveau_register_dsm_handler(void)
 	vga_switcheroo_register_handler(&nouveau_dsm_handler);
 }
 
+/* Must be called for Optimus models before the card can be turned off */
+void nouveau_switcheroo_optimus_dsm(void)
+{
+	u32 result = 0;
+	if (!nouveau_dsm_priv.optimus_detected)
+		return;
+
+	nouveau_optimus_dsm(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_OPTIMUS_FN,
+		NOUVEAU_DSM_OPTIMUS_ARGS, &result);
+}
+
 void nouveau_unregister_dsm_handler(void)
 {
 	vga_switcheroo_unregister_handler();
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 4c0be3a..061577c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -1041,6 +1041,7 @@ extern int  nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
 #if defined(CONFIG_ACPI)
 void nouveau_register_dsm_handler(void);
 void nouveau_unregister_dsm_handler(void);
+void nouveau_switcheroo_optimus_dsm(void);
 int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
 bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
 int nouveau_acpi_edid(struct drm_device *, struct drm_connector *);
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index d8831ab..ef270cf 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -525,6 +525,7 @@ static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
 		printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
 		dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
 		drm_kms_helper_poll_disable(dev);
+		nouveau_switcheroo_optimus_dsm();
 		nouveau_pci_suspend(pdev, pmm);
 		dev->switch_power_state = DRM_SWITCH_POWER_OFF;
 	}
-- 
1.7.5.4


[-- Attachment #3: Type: text/plain, Size: 181 bytes --]

_______________________________________________
Nouveau mailing list
Nouveau-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW@public.gmane.org
http://lists.freedesktop.org/mailman/listinfo/nouveau

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-01-12 17:29 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-17 12:14 properly check for _DSM function support and Optimus support for vga_switcheroo Lekensteyn
     [not found] ` <CALBR5ZxR9iuvT57bDZ8yW9ZkZjuoUhBTYw4HBsmsiwoRi4gSkw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-12-17 22:50   ` Lekensteyn
     [not found]     ` <CALBR5ZyE2ZRX7eFBhooB22e9BRf0f3H2xqtvXB2iwe8nvKKnvw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-12-19  4:39       ` Omar Andrés Zapata Mesa
     [not found]         ` <CAOB9epp8EdpetsPStfdnGNx5-2dKi42j3DQiVKN_dzMdFcssWA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-12-19  9:44           ` Lekensteyn
     [not found]             ` <CALBR5Zw0gEDqKrSUF3R30tSSC6DUgfhVm0Y1Mp60e4bB4ObijQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-12-19 10:04               ` Gianluca Cecchi
     [not found]                 ` <CAG2kNCwBwRJ_VrS9NHnmGvOTTLuwmBKd5kG8OknJG+f20Kvqsg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-12-19 13:26                   ` Lekensteyn
2012-01-08 23:13                     ` Lekensteyn
     [not found]                       ` <CALBR5Zxuwv-zBQfVr7By3su2rjWjcVapX7oCCfeybjBMPY9cbA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2012-01-09 22:45                         ` Ben Skeggs
2012-01-12 17:29                           ` Dave Airlie

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.