From 0e1133157986340e80a1c65ebf3bd20b74eb8075 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Thu, 12 Jan 2012 11:50:26 -0500 Subject: ttm/dma: Remove the WARN() which is not useful. . It was useful during development, but now on a production system we can get this (if the user forgot to upload the firmware): [drm] radeon: irq initialized. [drm] GART: num cpu pages 131072, num gpu pages 131072 [drm] radeon: ib pool ready. [drm] Loading SUMO Microcode r600_cp: Failed to load firmware "radeon/SUMO_pfp.bin" atl1c 0000:03:00.0: version 1.0.1.0-NAPI.213057] [drm:evergreen_startup] *ERROR* Failed to load firmware! radeon 0000:00:01.0: disabling GPU acceleration 88] radeon 0000:00:01.0: ffff8801bb782400 unpin not necessary ------------[ cut here ]------------ WARNING: at /home/konrad/linux-linus/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c:956 ttm_dma_unpopulate+0x79/0x300 [ttm]() Hardware name: System Product Name Modules linked in: e1000e atl1c radeon(+) ahci libahci libata scsi_mod fbcon tileblit font ttm bitblit softcursor drm_kms_helper wmi xen_blkfront xen_netfront fb_sys_fops sysimgblt sysfillrect syscopyarea xenfs xen_privcmd Pid: 1600, comm: modprobe Not tainted 3.2.0-06100-ge343a89 #1 Call Trace: [] warn_slowpath_common+0x7a/0xb0 [] warn_slowpath_null+0x15/0x20 [] ttm_dma_unpopulate+0x79/0x300 [ttm] [] radeon_ttm_tt_unpopulate+0x120/0x130 [radeon] [] ttm_tt_destroy+0x2c/0x70 [ttm] [] ttm_bo_cleanup_memtype_use+0x3e/0x80 [ttm] [] ttm_bo_release+0x251/0x280 [ttm] [] ttm_bo_unref+0x40/0x60 [ttm] [] radeon_bo_unref+0x42/0x80 [radeon] [] radeon_sa_bo_manager_fini+0x6b/0x80 [radeon] [] radeon_ib_pool_fini+0x6f/0x90 [radeon] [] r100_ib_fini+0x19/0x20 [radeon] [] evergreen_init+0x1ee/0x2d0 [radeon] The big WARN() has nothing to do with the culprit - which is that the firmware was not loaded. So lets remove the WARN() from the TTM DMA code. Signed-off-by: Konrad Rzeszutek Wilk Reviewed-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/ttm/ttm_page_alloc_dma.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c index 37ead6995c87..0c46d8cdc6ea 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc_dma.c @@ -952,10 +952,9 @@ void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev) type = ttm_to_type(ttm->page_flags, ttm->caching_state); pool = ttm_dma_find_pool(dev, type); - if (!pool) { - WARN_ON(!pool); + if (!pool) return; - } + is_cached = (ttm_dma_find_pool(pool->dev, ttm_to_type(ttm->page_flags, tt_cached)) == pool); -- cgit v1.2.3 From 0b41da60c0393d3c7b75b6c898fa1ee7c24a40db Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 12 Jan 2012 15:42:37 -0500 Subject: drm/radeon/kms/ni: fix packet2 handling for VM IB parser Packet2 is only one dword. Signed-off-by: Alex Deucher Reviewed-by: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/evergreen_cs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index f7442e62c03f..8e8cd85e5c00 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -1793,10 +1793,12 @@ int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) ret = -EINVAL; break; case PACKET_TYPE2: + idx += 1; break; case PACKET_TYPE3: pkt.opcode = CP_PACKET3_GET_OPCODE(ib->ptr[idx]); ret = evergreen_vm_packet3_check(rdev, ib->ptr, &pkt); + idx += pkt.count + 2; break; default: dev_err(rdev->dev, "Unknown packet type %d !\n", pkt.type); @@ -1805,7 +1807,6 @@ int evergreen_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib) } if (ret) break; - idx += pkt.count + 2; } while (idx < ib->length_dw); return ret; -- cgit v1.2.3 From 27d4d05220f84c2f83fe4c410fda0da479905813 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 30 Nov 2011 17:22:55 +0100 Subject: drm/radeon/kms: Fix module parameter description format Module parameter descriptions don't take a trailing \n, otherwise it breaks formatting of modinfo's output. Also add missing space after comma. Signed-off-by: Jean Delvare Cc: David Airlie Reviewed-by: Alex Deucher Cc: Jerome Glisse Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 31da622eef63..8032f1fedb11 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -145,7 +145,7 @@ module_param_named(vramlimit, radeon_vram_limit, int, 0600); MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)"); module_param_named(agpmode, radeon_agpmode, int, 0444); -MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32,64, etc)\n"); +MODULE_PARM_DESC(gartsize, "Size of PCIE/IGP gart to setup in megabytes (32, 64, etc)"); module_param_named(gartsize, radeon_gart_size, int, 0600); MODULE_PARM_DESC(benchmark, "Run benchmark"); -- cgit v1.2.3 From 9f821c675a389cf4aab7f1dc8ee0860fba4f3204 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 12 Jan 2012 14:40:12 +0000 Subject: gma500: Discard modes that don't fit in stolen memory [This fixes a crash on boot if the system is plugged into an HDTV so it's probably appropriate to push even though it didn't make the window. We could be cleverer about this but the simple version seems to be the safe one] From: Patrik Jakobsson At the moment we cannot allocate more than stolen memory size for framebuffers. To get around that issues we discard modes that doesn't fit. This is a temporary solution until we can freely allocate framebuffer memory. [Currently the framebuffer needs to be linear in kernel space due to limits in the kernel fb layer - AC] Signed-off-by: Patrik Jakobsson Signed-off-by: Alan Cox Signed-off-by: Dave Airlie --- drivers/gpu/drm/gma500/cdv_intel_crt.c | 6 ++++++ drivers/gpu/drm/gma500/cdv_intel_hdmi.c | 14 ++++++-------- drivers/gpu/drm/gma500/oaktrail_hdmi.c | 6 ++++++ drivers/gpu/drm/gma500/psb_intel_sdvo.c | 6 ++++++ 4 files changed, 24 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c index 6d0f10b7569c..c100f3e9c920 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_crt.c +++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c @@ -66,6 +66,7 @@ static void cdv_intel_crt_dpms(struct drm_encoder *encoder, int mode) static int cdv_intel_crt_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_psb_private *dev_priv = connector->dev->dev_private; int max_clock = 0; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; @@ -82,6 +83,11 @@ static int cdv_intel_crt_mode_valid(struct drm_connector *connector, if (mode->hdisplay > 1680 || mode->vdisplay > 1050) return MODE_PANEL; + /* We assume worst case scenario of 32 bpp here, since we don't know */ + if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) > + dev_priv->vram_stolen_size) + return MODE_MEM; + return MODE_OK; } diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index 50d7cfb51662..de25560e629d 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -241,6 +241,7 @@ static int cdv_hdmi_get_modes(struct drm_connector *connector) static int cdv_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_psb_private *dev_priv = connector->dev->dev_private; if (mode->clock > 165000) return MODE_CLOCK_HIGH; @@ -255,14 +256,11 @@ static int cdv_hdmi_mode_valid(struct drm_connector *connector, if (mode->flags & DRM_MODE_FLAG_INTERLACE) return MODE_NO_INTERLACE; - /* - * FIXME: for now we limit the size to 1680x1050 on CDV, otherwise it - * will go beyond the stolen memory size allocated to the framebuffer - */ - if (mode->hdisplay > 1680) - return MODE_PANEL; - if (mode->vdisplay > 1050) - return MODE_PANEL; + /* We assume worst case scenario of 32 bpp here, since we don't know */ + if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) > + dev_priv->vram_stolen_size) + return MODE_MEM; + return MODE_OK; } diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index 36878a60080d..025d30970cc0 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c @@ -506,6 +506,7 @@ int oaktrail_crtc_hdmi_mode_set(struct drm_crtc *crtc, static int oaktrail_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_psb_private *dev_priv = connector->dev->dev_private; if (mode->clock > 165000) return MODE_CLOCK_HIGH; if (mode->clock < 20000) @@ -514,6 +515,11 @@ static int oaktrail_hdmi_mode_valid(struct drm_connector *connector, if (mode->flags & DRM_MODE_FLAG_DBLSCAN) return MODE_NO_DBLESCAN; + /* We assume worst case scenario of 32 bpp here, since we don't know */ + if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) > + dev_priv->vram_stolen_size) + return MODE_MEM; + return MODE_OK; } diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index 4882b29119e0..88b42971c0fd 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -1141,6 +1141,7 @@ static void psb_intel_sdvo_dpms(struct drm_encoder *encoder, int mode) static int psb_intel_sdvo_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_psb_private *dev_priv = connector->dev->dev_private; struct psb_intel_sdvo *psb_intel_sdvo = intel_attached_sdvo(connector); if (mode->flags & DRM_MODE_FLAG_DBLSCAN) @@ -1160,6 +1161,11 @@ static int psb_intel_sdvo_mode_valid(struct drm_connector *connector, return MODE_PANEL; } + /* We assume worst case scenario of 32 bpp here, since we don't know */ + if ((ALIGN(mode->hdisplay * 4, 64) * mode->vdisplay) > + dev_priv->vram_stolen_size) + return MODE_MEM; + return MODE_OK; } -- cgit v1.2.3 From 642ce5251b4fefdb8f2a55396707b8fa9f953e05 Mon Sep 17 00:00:00 2001 From: Michel Dänzer Date: Thu, 12 Jan 2012 16:04:11 +0100 Subject: radeon: Call pci_clear_master() instead of open-coding it. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: Ben Hutchings Signed-off-by: Michel Dänzer Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/r100.c | 4 +--- drivers/gpu/drm/radeon/rs600.c | 13 ++----------- 2 files changed, 3 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 3ec81c3d5108..bfd36ab643a6 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2186,7 +2186,6 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring) void r100_bm_disable(struct radeon_device *rdev) { u32 tmp; - u16 tmp16; /* disable bus mastering */ tmp = RREG32(R_000030_BUS_CNTL); @@ -2197,8 +2196,7 @@ void r100_bm_disable(struct radeon_device *rdev) WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040); tmp = RREG32(RADEON_BUS_CNTL); mdelay(1); - pci_read_config_word(rdev->pdev, 0x4, &tmp16); - pci_write_config_word(rdev->pdev, 0x4, tmp16 & 0xFFFB); + pci_clear_master(rdev->pdev); mdelay(1); } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 803e0d3c1773..ec46eb45e34c 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -322,16 +322,6 @@ void rs600_hpd_fini(struct radeon_device *rdev) } } -void rs600_bm_disable(struct radeon_device *rdev) -{ - u16 tmp; - - /* disable bus mastering */ - pci_read_config_word(rdev->pdev, 0x4, &tmp); - pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB); - mdelay(1); -} - int rs600_asic_reset(struct radeon_device *rdev) { struct rv515_mc_save save; @@ -355,7 +345,8 @@ int rs600_asic_reset(struct radeon_device *rdev) WREG32(RADEON_CP_RB_CNTL, tmp); pci_save_state(rdev->pdev); /* disable bus mastering */ - rs600_bm_disable(rdev); + pci_clear_master(rdev->pdev); + mdelay(1); /* reset GA+VAP */ WREG32(R_0000F0_RBBM_SOFT_RESET, S_0000F0_SOFT_RESET_VAP(1) | S_0000F0_SOFT_RESET_GA(1)); -- cgit v1.2.3 From 3b32a592ea6e49145d4dc610b85dd9042226896d Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 13 Jan 2012 09:05:14 +0000 Subject: dma-buf: drop option text so users don't select it. This is going to be used by other subsystems so they should select it. Signed-off-by: Dave Airlie --- drivers/base/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig index fcbec8ac134d..7be9f79018e9 100644 --- a/drivers/base/Kconfig +++ b/drivers/base/Kconfig @@ -179,7 +179,7 @@ config GENERIC_CPU_DEVICES source "drivers/base/regmap/Kconfig" config DMA_SHARED_BUFFER - bool "Buffer framework to be shared between drivers" + bool default n select ANON_INODES depends on EXPERIMENTAL -- cgit v1.2.3 From 9075e85f46c598e4dfc852b16b256a32e2fb396f Mon Sep 17 00:00:00 2001 From: Peter Lekensteyn Date: Sat, 17 Dec 2011 12:53:43 +0100 Subject: 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 Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nouveau_acpi.c | 35 +++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 525744d593c1..96756d0d6411 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -18,12 +18,6 @@ #include -#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) -- cgit v1.2.3 From d099230cc355c485e556121c034b1fca5a5fd18b Mon Sep 17 00:00:00 2001 From: Peter Lekensteyn Date: Sat, 17 Dec 2011 12:54:04 +0100 Subject: 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 Signed-off-by: Dave Airlie --- 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(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 96756d0d6411..7814a760c164 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 38134a9c7578..b82709828931 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1055,12 +1055,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 f5e98910d17f..f80c5e0762ff 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; } -- cgit v1.2.3