Commit 112b715e authored by Kristian Høgsberg's avatar Kristian Høgsberg Committed by Dave Airlie

drm: claim PCI device when running in modesetting mode.

Under kernel modesetting, we manage the device at all times, regardless
of VT switching and X servers, so the only decent thing to do is to
claim the PCI device.  In that case, we call the suspend/resume hooks
directly from the pci driver hooks instead of the current class device detour.
Signed-off-by: default avatarKristian Høgsberg <krh@redhat.com>
Signed-off-by: default avatarDave Airlie <airlied@linux.ie>
parent 41c2e75e
...@@ -252,15 +252,19 @@ int drm_lastclose(struct drm_device * dev) ...@@ -252,15 +252,19 @@ int drm_lastclose(struct drm_device * dev)
int drm_init(struct drm_driver *driver) int drm_init(struct drm_driver *driver)
{ {
struct pci_dev *pdev = NULL; struct pci_dev *pdev = NULL;
struct pci_device_id *pid; const struct pci_device_id *pid;
int i; int i;
DRM_DEBUG("\n"); DRM_DEBUG("\n");
INIT_LIST_HEAD(&driver->device_list); INIT_LIST_HEAD(&driver->device_list);
if (driver->driver_features & DRIVER_MODESET)
return pci_register_driver(&driver->pci_driver);
/* If not using KMS, fall back to stealth mode manual scanning. */
for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) { for (i = 0; driver->pci_driver.id_table[i].vendor != 0; i++) {
pid = (struct pci_device_id *)&driver->pci_driver.id_table[i]; pid = &driver->pci_driver.id_table[i];
/* Loop around setting up a DRM device for each PCI device /* Loop around setting up a DRM device for each PCI device
* matching our ID and device class. If we had the internal * matching our ID and device class. If we had the internal
...@@ -285,68 +289,17 @@ int drm_init(struct drm_driver *driver) ...@@ -285,68 +289,17 @@ int drm_init(struct drm_driver *driver)
EXPORT_SYMBOL(drm_init); EXPORT_SYMBOL(drm_init);
/**
* Called via cleanup_module() at module unload time.
*
* Cleans up all DRM device, calling drm_lastclose().
*
* \sa drm_init
*/
static void drm_cleanup(struct drm_device * dev)
{
struct drm_map_list *r_list, *list_temp;
DRM_DEBUG("\n");
if (!dev) {
DRM_ERROR("cleanup called no dev\n");
return;
}
drm_vblank_cleanup(dev);
drm_lastclose(dev);
if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
dev->agp && dev->agp->agp_mtrr >= 0) {
int retval;
retval = mtrr_del(dev->agp->agp_mtrr,
dev->agp->agp_info.aper_base,
dev->agp->agp_info.aper_size * 1024 * 1024);
DRM_DEBUG("mtrr_del=%d\n", retval);
}
if (dev->driver->unload)
dev->driver->unload(dev);
if (drm_core_has_AGP(dev) && dev->agp) {
drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
dev->agp = NULL;
}
drm_ht_remove(&dev->map_hash);
drm_ctxbitmap_cleanup(dev);
list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
drm_rmmap(dev, r_list->map);
if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_put_minor(&dev->control);
if (dev->driver->driver_features & DRIVER_GEM)
drm_gem_destroy(dev);
drm_put_minor(&dev->primary);
if (drm_put_dev(dev))
DRM_ERROR("Cannot unload module\n");
}
void drm_exit(struct drm_driver *driver) void drm_exit(struct drm_driver *driver)
{ {
struct drm_device *dev, *tmp; struct drm_device *dev, *tmp;
DRM_DEBUG("\n"); DRM_DEBUG("\n");
if (driver->driver_features & DRIVER_MODESET) {
pci_unregister_driver(&driver->pci_driver);
} else {
list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item) list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
drm_cleanup(dev); drm_put_dev(dev);
}
DRM_INFO("Module unloaded\n"); DRM_INFO("Module unloaded\n");
} }
......
...@@ -372,6 +372,7 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, ...@@ -372,6 +372,7 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
} }
if (drm_core_check_feature(dev, DRIVER_MODESET)) { if (drm_core_check_feature(dev, DRIVER_MODESET)) {
pci_set_drvdata(pdev, dev);
ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL); ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
if (ret) if (ret)
goto err_g2; goto err_g2;
...@@ -409,29 +410,7 @@ err_g1: ...@@ -409,29 +410,7 @@ err_g1:
drm_free(dev, sizeof(*dev), DRM_MEM_STUB); drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
return ret; return ret;
} }
EXPORT_SYMBOL(drm_get_dev);
/**
* Put a device minor number.
*
* \param dev device data structure
* \return always zero
*
* Cleans up the proc resources. If it is the last minor then release the foreign
* "drm" data, otherwise unregisters the "drm" data, frees the dev list and
* unregisters the character device.
*/
int drm_put_dev(struct drm_device * dev)
{
DRM_DEBUG("release primary %s\n", dev->driver->pci_driver.name);
if (dev->devname) {
drm_free(dev->devname, strlen(dev->devname) + 1,
DRM_MEM_DRIVER);
dev->devname = NULL;
}
drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
return 0;
}
/** /**
* Put a secondary minor number. * Put a secondary minor number.
...@@ -459,3 +438,67 @@ int drm_put_minor(struct drm_minor **minor_p) ...@@ -459,3 +438,67 @@ int drm_put_minor(struct drm_minor **minor_p)
*minor_p = NULL; *minor_p = NULL;
return 0; return 0;
} }
/**
* Called via drm_exit() at module unload time or when pci device is
* unplugged.
*
* Cleans up all DRM device, calling drm_lastclose().
*
* \sa drm_init
*/
void drm_put_dev(struct drm_device *dev)
{
struct drm_driver *driver = dev->driver;
struct drm_map_list *r_list, *list_temp;
DRM_DEBUG("\n");
if (!dev) {
DRM_ERROR("cleanup called no dev\n");
return;
}
drm_vblank_cleanup(dev);
drm_lastclose(dev);
if (drm_core_has_MTRR(dev) && drm_core_has_AGP(dev) &&
dev->agp && dev->agp->agp_mtrr >= 0) {
int retval;
retval = mtrr_del(dev->agp->agp_mtrr,
dev->agp->agp_info.aper_base,
dev->agp->agp_info.aper_size * 1024 * 1024);
DRM_DEBUG("mtrr_del=%d\n", retval);
}
if (dev->driver->unload)
dev->driver->unload(dev);
if (drm_core_has_AGP(dev) && dev->agp) {
drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS);
dev->agp = NULL;
}
drm_ht_remove(&dev->map_hash);
drm_ctxbitmap_cleanup(dev);
list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
drm_rmmap(dev, r_list->map);
if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_put_minor(&dev->control);
if (driver->driver_features & DRIVER_GEM)
drm_gem_destroy(dev);
drm_put_minor(&dev->primary);
if (dev->devname) {
drm_free(dev->devname, strlen(dev->devname) + 1,
DRM_MEM_DRIVER);
dev->devname = NULL;
}
drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
}
EXPORT_SYMBOL(drm_put_dev);
...@@ -35,7 +35,9 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) ...@@ -35,7 +35,9 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state)
struct drm_minor *drm_minor = to_drm_minor(dev); struct drm_minor *drm_minor = to_drm_minor(dev);
struct drm_device *drm_dev = drm_minor->dev; struct drm_device *drm_dev = drm_minor->dev;
if (drm_minor->type == DRM_MINOR_LEGACY && drm_dev->driver->suspend) if (drm_minor->type == DRM_MINOR_LEGACY &&
!drm_core_check_feature(drm_dev, DRIVER_MODESET) &&
drm_dev->driver->suspend)
return drm_dev->driver->suspend(drm_dev, state); return drm_dev->driver->suspend(drm_dev, state);
return 0; return 0;
...@@ -53,7 +55,9 @@ static int drm_sysfs_resume(struct device *dev) ...@@ -53,7 +55,9 @@ static int drm_sysfs_resume(struct device *dev)
struct drm_minor *drm_minor = to_drm_minor(dev); struct drm_minor *drm_minor = to_drm_minor(dev);
struct drm_device *drm_dev = drm_minor->dev; struct drm_device *drm_dev = drm_minor->dev;
if (drm_minor->type == DRM_MINOR_LEGACY && drm_dev->driver->resume) if (drm_minor->type == DRM_MINOR_LEGACY &&
!drm_core_check_feature(drm_dev, DRIVER_MODESET) &&
drm_dev->driver->resume)
return drm_dev->driver->resume(drm_dev); return drm_dev->driver->resume(drm_dev);
return 0; return 0;
......
...@@ -42,6 +42,8 @@ module_param_named(modeset, i915_modeset, int, 0400); ...@@ -42,6 +42,8 @@ module_param_named(modeset, i915_modeset, int, 0400);
unsigned int i915_fbpercrtc = 0; unsigned int i915_fbpercrtc = 0;
module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400); module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
static struct drm_driver driver;
static struct pci_device_id pciidlist[] = { static struct pci_device_id pciidlist[] = {
i915_PCI_IDS i915_PCI_IDS
}; };
...@@ -117,6 +119,36 @@ static int i915_resume(struct drm_device *dev) ...@@ -117,6 +119,36 @@ static int i915_resume(struct drm_device *dev)
return ret; return ret;
} }
static int __devinit
i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
return drm_get_dev(pdev, ent, &driver);
}
static void
i915_pci_remove(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
drm_put_dev(dev);
}
static int
i915_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct drm_device *dev = pci_get_drvdata(pdev);
return i915_suspend(dev, state);
}
static int
i915_pci_resume(struct pci_dev *pdev)
{
struct drm_device *dev = pci_get_drvdata(pdev);
return i915_resume(dev);
}
static struct vm_operations_struct i915_gem_vm_ops = { static struct vm_operations_struct i915_gem_vm_ops = {
.fault = i915_gem_fault, .fault = i915_gem_fault,
.open = drm_gem_vm_open, .open = drm_gem_vm_open,
...@@ -172,6 +204,12 @@ static struct drm_driver driver = { ...@@ -172,6 +204,12 @@ static struct drm_driver driver = {
.pci_driver = { .pci_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.id_table = pciidlist, .id_table = pciidlist,
.probe = i915_pci_probe,
.remove = i915_pci_remove,
#ifdef CONFIG_PM
.resume = i915_pci_resume,
.suspend = i915_pci_suspend,
#endif
}, },
.name = DRIVER_NAME, .name = DRIVER_NAME,
......
...@@ -1265,7 +1265,7 @@ extern struct drm_master *drm_master_get(struct drm_master *master); ...@@ -1265,7 +1265,7 @@ extern struct drm_master *drm_master_get(struct drm_master *master);
extern void drm_master_put(struct drm_master **master); extern void drm_master_put(struct drm_master **master);
extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
struct drm_driver *driver); struct drm_driver *driver);
extern int drm_put_dev(struct drm_device *dev); extern void drm_put_dev(struct drm_device *dev);
extern int drm_put_minor(struct drm_minor **minor); extern int drm_put_minor(struct drm_minor **minor);
extern unsigned int drm_debug; extern unsigned int drm_debug;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment