diff options
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 168 |
1 files changed, 101 insertions, 67 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index ecac882e1d54..79beffcf5936 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
| @@ -174,78 +174,100 @@ const static struct pci_device_id pciidlist[] = { | |||
| 174 | MODULE_DEVICE_TABLE(pci, pciidlist); | 174 | MODULE_DEVICE_TABLE(pci, pciidlist); |
| 175 | #endif | 175 | #endif |
| 176 | 176 | ||
| 177 | static int i915_suspend(struct drm_device *dev, pm_message_t state) | 177 | static int i915_drm_freeze(struct drm_device *dev) |
| 178 | { | 178 | { |
| 179 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 180 | |||
| 181 | if (!dev || !dev_priv) { | ||
| 182 | DRM_ERROR("dev: %p, dev_priv: %p\n", dev, dev_priv); | ||
| 183 | DRM_ERROR("DRM not initialized, aborting suspend.\n"); | ||
| 184 | return -ENODEV; | ||
| 185 | } | ||
| 186 | |||
| 187 | if (state.event == PM_EVENT_PRETHAW) | ||
| 188 | return 0; | ||
| 189 | |||
| 190 | pci_save_state(dev->pdev); | 179 | pci_save_state(dev->pdev); |
| 191 | 180 | ||
| 192 | /* If KMS is active, we do the leavevt stuff here */ | 181 | /* If KMS is active, we do the leavevt stuff here */ |
| 193 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | 182 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
| 194 | if (i915_gem_idle(dev)) | 183 | int error = i915_gem_idle(dev); |
| 184 | if (error) { | ||
| 195 | dev_err(&dev->pdev->dev, | 185 | dev_err(&dev->pdev->dev, |
| 196 | "GEM idle failed, resume may fail\n"); | 186 | "GEM idle failed, resume might fail\n"); |
| 187 | return error; | ||
| 188 | } | ||
| 197 | drm_irq_uninstall(dev); | 189 | drm_irq_uninstall(dev); |
| 198 | } | 190 | } |
| 199 | 191 | ||
| 200 | i915_save_state(dev); | 192 | i915_save_state(dev); |
| 201 | 193 | ||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | static void i915_drm_suspend(struct drm_device *dev) | ||
| 198 | { | ||
| 199 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
| 200 | |||
| 202 | intel_opregion_free(dev, 1); | 201 | intel_opregion_free(dev, 1); |
| 203 | 202 | ||
| 203 | /* Modeset on resume, not lid events */ | ||
| 204 | dev_priv->modeset_on_lid = 0; | ||
| 205 | } | ||
| 206 | |||
| 207 | static int i915_suspend(struct drm_device *dev, pm_message_t state) | ||
| 208 | { | ||
| 209 | int error; | ||
| 210 | |||
| 211 | if (!dev || !dev->dev_private) { | ||
| 212 | DRM_ERROR("dev: %p\n", dev); | ||
| 213 | DRM_ERROR("DRM not initialized, aborting suspend.\n"); | ||
| 214 | return -ENODEV; | ||
| 215 | } | ||
| 216 | |||
| 217 | if (state.event == PM_EVENT_PRETHAW) | ||
| 218 | return 0; | ||
| 219 | |||
| 220 | error = i915_drm_freeze(dev); | ||
| 221 | if (error) | ||
| 222 | return error; | ||
| 223 | |||
| 224 | i915_drm_suspend(dev); | ||
| 225 | |||
| 204 | if (state.event == PM_EVENT_SUSPEND) { | 226 | if (state.event == PM_EVENT_SUSPEND) { |
| 205 | /* Shut down the device */ | 227 | /* Shut down the device */ |
| 206 | pci_disable_device(dev->pdev); | 228 | pci_disable_device(dev->pdev); |
| 207 | pci_set_power_state(dev->pdev, PCI_D3hot); | 229 | pci_set_power_state(dev->pdev, PCI_D3hot); |
| 208 | } | 230 | } |
| 209 | 231 | ||
| 210 | /* Modeset on resume, not lid events */ | ||
| 211 | dev_priv->modeset_on_lid = 0; | ||
| 212 | |||
| 213 | return 0; | 232 | return 0; |
| 214 | } | 233 | } |
| 215 | 234 | ||
| 216 | static int i915_resume(struct drm_device *dev) | 235 | static int i915_drm_thaw(struct drm_device *dev) |
| 217 | { | 236 | { |
| 218 | struct drm_i915_private *dev_priv = dev->dev_private; | 237 | struct drm_i915_private *dev_priv = dev->dev_private; |
| 219 | int ret = 0; | 238 | int error = 0; |
| 220 | |||
| 221 | if (pci_enable_device(dev->pdev)) | ||
| 222 | return -1; | ||
| 223 | pci_set_master(dev->pdev); | ||
| 224 | |||
| 225 | i915_restore_state(dev); | ||
| 226 | |||
| 227 | intel_opregion_init(dev, 1); | ||
| 228 | 239 | ||
| 229 | /* KMS EnterVT equivalent */ | 240 | /* KMS EnterVT equivalent */ |
| 230 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | 241 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { |
| 231 | mutex_lock(&dev->struct_mutex); | 242 | mutex_lock(&dev->struct_mutex); |
| 232 | dev_priv->mm.suspended = 0; | 243 | dev_priv->mm.suspended = 0; |
| 233 | 244 | ||
| 234 | ret = i915_gem_init_ringbuffer(dev); | 245 | error = i915_gem_init_ringbuffer(dev); |
| 235 | if (ret != 0) | ||
| 236 | ret = -1; | ||
| 237 | mutex_unlock(&dev->struct_mutex); | 246 | mutex_unlock(&dev->struct_mutex); |
| 238 | 247 | ||
| 239 | drm_irq_install(dev); | 248 | drm_irq_install(dev); |
| 240 | } | 249 | |
| 241 | if (drm_core_check_feature(dev, DRIVER_MODESET)) { | ||
| 242 | /* Resume the modeset for every activated CRTC */ | 250 | /* Resume the modeset for every activated CRTC */ |
| 243 | drm_helper_resume_force_mode(dev); | 251 | drm_helper_resume_force_mode(dev); |
| 244 | } | 252 | } |
| 245 | 253 | ||
| 246 | dev_priv->modeset_on_lid = 0; | 254 | dev_priv->modeset_on_lid = 0; |
| 247 | 255 | ||
| 248 | return ret; | 256 | return error; |
| 257 | } | ||
| 258 | |||
| 259 | static int i915_resume(struct drm_device *dev) | ||
| 260 | { | ||
| 261 | if (pci_enable_device(dev->pdev)) | ||
| 262 | return -EIO; | ||
| 263 | |||
| 264 | pci_set_master(dev->pdev); | ||
| 265 | |||
| 266 | i915_restore_state(dev); | ||
| 267 | |||
| 268 | intel_opregion_init(dev, 1); | ||
| 269 | |||
| 270 | return i915_drm_thaw(dev); | ||
| 249 | } | 271 | } |
| 250 | 272 | ||
| 251 | /** | 273 | /** |
| @@ -386,57 +408,69 @@ i915_pci_remove(struct pci_dev *pdev) | |||
| 386 | drm_put_dev(dev); | 408 | drm_put_dev(dev); |
| 387 | } | 409 | } |
| 388 | 410 | ||
| 389 | static int | 411 | static int i915_pm_suspend(struct device *dev) |
| 390 | i915_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
| 391 | { | 412 | { |
| 392 | struct drm_device *dev = pci_get_drvdata(pdev); | 413 | struct pci_dev *pdev = to_pci_dev(dev); |
| 414 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
| 415 | int error; | ||
| 393 | 416 | ||
| 394 | return i915_suspend(dev, state); | 417 | if (!drm_dev || !drm_dev->dev_private) { |
| 395 | } | 418 | dev_err(dev, "DRM not initialized, aborting suspend.\n"); |
| 419 | return -ENODEV; | ||
| 420 | } | ||
| 396 | 421 | ||
| 397 | static int | 422 | error = i915_drm_freeze(drm_dev); |
| 398 | i915_pci_resume(struct pci_dev *pdev) | 423 | if (error) |
| 399 | { | 424 | return error; |
| 400 | struct drm_device *dev = pci_get_drvdata(pdev); | ||
| 401 | 425 | ||
| 402 | return i915_resume(dev); | 426 | i915_drm_suspend(drm_dev); |
| 403 | } | ||
| 404 | 427 | ||
| 405 | static int | 428 | pci_disable_device(pdev); |
| 406 | i915_pm_suspend(struct device *dev) | 429 | pci_set_power_state(pdev, PCI_D3hot); |
| 407 | { | ||
| 408 | return i915_pci_suspend(to_pci_dev(dev), PMSG_SUSPEND); | ||
| 409 | } | ||
| 410 | 430 | ||
| 411 | static int | 431 | return 0; |
| 412 | i915_pm_resume(struct device *dev) | ||
| 413 | { | ||
| 414 | return i915_pci_resume(to_pci_dev(dev)); | ||
| 415 | } | 432 | } |
| 416 | 433 | ||
| 417 | static int | 434 | static int i915_pm_resume(struct device *dev) |
| 418 | i915_pm_freeze(struct device *dev) | ||
| 419 | { | 435 | { |
| 420 | return i915_pci_suspend(to_pci_dev(dev), PMSG_FREEZE); | 436 | struct pci_dev *pdev = to_pci_dev(dev); |
| 437 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
| 438 | |||
| 439 | return i915_resume(drm_dev); | ||
| 421 | } | 440 | } |
| 422 | 441 | ||
| 423 | static int | 442 | static int i915_pm_freeze(struct device *dev) |
| 424 | i915_pm_thaw(struct device *dev) | ||
| 425 | { | 443 | { |
| 426 | /* thaw during hibernate, do nothing! */ | 444 | struct pci_dev *pdev = to_pci_dev(dev); |
| 427 | return 0; | 445 | struct drm_device *drm_dev = pci_get_drvdata(pdev); |
| 446 | |||
| 447 | if (!drm_dev || !drm_dev->dev_private) { | ||
| 448 | dev_err(dev, "DRM not initialized, aborting suspend.\n"); | ||
| 449 | return -ENODEV; | ||
| 450 | } | ||
| 451 | |||
| 452 | return i915_drm_freeze(drm_dev); | ||
| 428 | } | 453 | } |
| 429 | 454 | ||
| 430 | static int | 455 | static int i915_pm_thaw(struct device *dev) |
| 431 | i915_pm_poweroff(struct device *dev) | ||
| 432 | { | 456 | { |
| 433 | return i915_pci_suspend(to_pci_dev(dev), PMSG_HIBERNATE); | 457 | struct pci_dev *pdev = to_pci_dev(dev); |
| 458 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
| 459 | |||
| 460 | return i915_drm_thaw(drm_dev); | ||
| 434 | } | 461 | } |
| 435 | 462 | ||
| 436 | static int | 463 | static int i915_pm_poweroff(struct device *dev) |
| 437 | i915_pm_restore(struct device *dev) | ||
| 438 | { | 464 | { |
| 439 | return i915_pci_resume(to_pci_dev(dev)); | 465 | struct pci_dev *pdev = to_pci_dev(dev); |
| 466 | struct drm_device *drm_dev = pci_get_drvdata(pdev); | ||
| 467 | int error; | ||
| 468 | |||
| 469 | error = i915_drm_freeze(drm_dev); | ||
| 470 | if (!error) | ||
| 471 | i915_drm_suspend(drm_dev); | ||
| 472 | |||
| 473 | return error; | ||
| 440 | } | 474 | } |
| 441 | 475 | ||
| 442 | const struct dev_pm_ops i915_pm_ops = { | 476 | const struct dev_pm_ops i915_pm_ops = { |
| @@ -445,7 +479,7 @@ const struct dev_pm_ops i915_pm_ops = { | |||
| 445 | .freeze = i915_pm_freeze, | 479 | .freeze = i915_pm_freeze, |
| 446 | .thaw = i915_pm_thaw, | 480 | .thaw = i915_pm_thaw, |
| 447 | .poweroff = i915_pm_poweroff, | 481 | .poweroff = i915_pm_poweroff, |
| 448 | .restore = i915_pm_restore, | 482 | .restore = i915_pm_resume, |
| 449 | }; | 483 | }; |
| 450 | 484 | ||
| 451 | static struct vm_operations_struct i915_gem_vm_ops = { | 485 | static struct vm_operations_struct i915_gem_vm_ops = { |
