Skip to content

Commit

Permalink
drm: claim PCI device when running in modesetting mode.
Browse files Browse the repository at this point in the history
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: Kristian Høgsberg <krh@redhat.com>
Signed-off-by: Dave Airlie <airlied@linux.ie>
  • Loading branch information
Kristian Høgsberg authored and Dave Airlie committed Mar 13, 2009
1 parent 41c2e75 commit 112b715
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 85 deletions.
71 changes: 12 additions & 59 deletions drivers/gpu/drm/drm_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,15 +252,19 @@ int drm_lastclose(struct drm_device * dev)
int drm_init(struct drm_driver *driver)
{
struct pci_dev *pdev = NULL;
struct pci_device_id *pid;
const struct pci_device_id *pid;
int i;

DRM_DEBUG("\n");

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++) {
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
* matching our ID and device class. If we had the internal
Expand All @@ -285,68 +289,17 @@ int drm_init(struct drm_driver *driver)

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)
{
struct drm_device *dev, *tmp;
DRM_DEBUG("\n");

list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
drm_cleanup(dev);
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)
drm_put_dev(dev);
}

DRM_INFO("Module unloaded\n");
}
Expand Down
89 changes: 66 additions & 23 deletions drivers/gpu/drm/drm_stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
pci_set_drvdata(pdev, dev);
ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
if (ret)
goto err_g2;
Expand Down Expand Up @@ -409,29 +410,7 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
return ret;
}

/**
* 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;
}
EXPORT_SYMBOL(drm_get_dev);

/**
* Put a secondary minor number.
Expand Down Expand Up @@ -459,3 +438,67 @@ int drm_put_minor(struct drm_minor **minor_p)
*minor_p = NULL;
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);
8 changes: 6 additions & 2 deletions drivers/gpu/drm/drm_sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_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 0;
Expand All @@ -53,7 +55,9 @@ static int drm_sysfs_resume(struct device *dev)
struct drm_minor *drm_minor = to_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 0;
Expand Down
38 changes: 38 additions & 0 deletions drivers/gpu/drm/i915/i915_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ module_param_named(modeset, i915_modeset, int, 0400);
unsigned int i915_fbpercrtc = 0;
module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);

static struct drm_driver driver;

static struct pci_device_id pciidlist[] = {
i915_PCI_IDS
};
Expand Down Expand Up @@ -117,6 +119,36 @@ static int i915_resume(struct drm_device *dev)
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 = {
.fault = i915_gem_fault,
.open = drm_gem_vm_open,
Expand Down Expand Up @@ -172,6 +204,12 @@ static struct drm_driver driver = {
.pci_driver = {
.name = DRIVER_NAME,
.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,
Expand Down
2 changes: 1 addition & 1 deletion include/drm/drmP.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
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 unsigned int drm_debug;

Expand Down

0 comments on commit 112b715

Please sign in to comment.