Any activity on this? The newly attached patch contains one difference with the previous one: a dummy function has been added to avoid an error if ACPI is disabled.
Regards, Lekensteyn On Mon, Dec 19, 2011 at 2:26 PM, Lekensteyn <[email protected]> wrote: > A quickly written way to test this module is described for Ubuntu at > http://pastebin.com/c5XqKSsW. Basically, you need to apply the patch on > nouveau > and rebuild the nouveau kernel module. > > A comparison of different methods that works for toggling the dGPU is > available: > > https://github.com/Bumblebee-Project/Bumblebee/wiki/Comparison-of-PM-methods > > Regards, > Lekensteyn > > > On Mon, Dec 19, 2011 at 11:04 AM, Gianluca Cecchi < > [email protected]> wrote: > >> >> On Sat, Dec 17, 2011 at 5:50 PM, Lekensteyn <[email protected]> >> wrote: >> >>> >> >>> 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 >> >> Hello, >> I have an Asus U36SD laptop with Optimus and Fedora 16 with kernel >> 3.1.5-6.fc16.x86_64 >> Any way I can test it? >> Currently I'm using acpi_call to switch off nvidia card and gain 4w >> for more battery life. >> >> [g.cecchi@ope46 ~]$ lspci -vnnn|grep -i vga >> 00:02.0 VGA compatible controller [0300]: Intel Corporation 2nd >> Generation Core Processor Family Integrated Graphics Controller >> [8086:0126] (rev 09) (prog-if 00 [VGA controller]) >> 01:00.0 VGA compatible controller [0300]: nVidia Corporation Device >> [10de:1050] (rev ff) (prog-if ff) >> >> What benefit would it give me? Chance to use nvidia for graphic >> related apps ? With nouveau andor nvidia proprietary driver? >> Thanks in advance for any pointer >> >> Gianluca >> _______________________________________________ >> Nouveau mailing list >> [email protected] >> http://lists.freedesktop.org/mailman/listinfo/nouveau >> > >
From b6e1b5b316ae17ccb7def0a8b38e69ad4c99c55d Mon Sep 17 00:00:00 2001 From: Peter Lekensteyn <[email protected]> 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 <[email protected]> --- 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 9c1a466321c9bdc44fb45205ebb5469da3d2adba Mon Sep 17 00:00:00 2001 From: Peter Lekensteyn <[email protected]> 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 <[email protected]> --- drivers/gpu/drm/nouveau/nouveau_acpi.c | 44 +++++++++++++++++++++++++++--- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 + drivers/gpu/drm/nouveau/nouveau_state.c | 1 + 3 files changed, 42 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..4f369f4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1041,12 +1041,14 @@ 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 *); #else static inline void nouveau_register_dsm_handler(void) {} static inline void nouveau_unregister_dsm_handler(void) {} +static inline void nouveau_switcheroo_optimus_dsm(void) {} static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; } static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; } static inline int nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return -EINVAL; } 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
_______________________________________________ Nouveau mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/nouveau
