Please do not reply to this email: if you want to comment on the bug, go to the URL shown below and enter yourcomments there. https://bugs.freedesktop.org/show_bug.cgi?id=3549 Summary: drm power management does not dereference sysdev correctly Product: DRI Version: DRI CVS Platform: Other OS/Version: Linux Status: NEW Severity: normal Priority: P2 Component: DRM modules AssignedTo: dri-devel@lists.sourceforge.net ReportedBy: [EMAIL PROTECTED]
In linux-core drm_pm.c, CVS version 1.1, the drm_pm_setup function registers the drm device's sysdev field with the power manager, but when the drm_suspend or drm_resume functions are called, the functions think that they have received a drm_device ptr, and not a power management sys_device ptr, and perform an incorrect typecast. They dereference the sys_device as if it were a drm_device, get an invalid value for the drm driver field, and go off into the weeds. Another issue is that Linux kernel 2.6.11 (?) has changed the argument that it passes to power management functions from an unsigned int to a pm_message_t struct. The attached patch fixes this behavior using a union struct, and also makes drm_pm.c and drmP.h compatible with the new style pm_message_t arguments. Unfortunately it doesn't preserve backward compatibility with older kernels. Index: drmP.h =================================================================== RCS file: /cvs/dri/drm/linux-core/drmP.h,v retrieving revision 1.147 diff -c -r1.147 drmP.h *** drmP.h 4 Jun 2005 06:18:10 -0000 1.147 --- drmP.h 16 Jun 2005 13:09:59 -0000 *************** *** 515,520 **** --- 515,534 ---- struct task_struct *task; } drm_vbl_sig_t; + + /** + * union struct that can either be a PM sys_device or a drm_sys_device + */ + typedef struct drm_sysdev { + struct sys_device sysdev; + struct drm_device* dev; + } drm_sysdev_t; + + union drm_sysdev_data { + struct sys_device sysdev; + struct drm_sysdev drmdev; + }; + /** * DRM driver structure. This structure represent the common code for * a family of cards. There will one drm_device for each card present *************** *** 723,729 **** drm_local_map_t *agp_buffer_map; drm_head_t primary; /**< primary screen head */ ! struct sys_device sysdev; /**< Power Management device structure */ int sysdev_registered; /**< Whether the device has been registered */ } drm_device_t; --- 737,743 ---- drm_local_map_t *agp_buffer_map; drm_head_t primary; /**< primary screen head */ ! union drm_sysdev_data sysdev; /** union PM structure */ int sysdev_registered; /**< Whether the device has been registered */ } drm_device_t; Index: drm_pm.c =================================================================== RCS file: /cvs/dri/drm/linux-core/drm_pm.c,v retrieving revision 1.1 diff -c -r1.1 drm_pm.c *** drm_pm.c 28 May 2005 00:00:08 -0000 1.1 --- drm_pm.c 16 Jun 2005 13:09:59 -0000 *************** *** 36,56 **** #include <linux/device.h> #include <linux/sysdev.h> ! static int drm_suspend(struct sys_device *sysdev, u32 state) { ! drm_device_t *dev = (drm_device_t *)sysdev; ! ! DRM_DEBUG("%s state=%d\n", __FUNCTION__, state); if (dev->driver->power) ! return dev->driver->power(dev, state); else return 0; } static int drm_resume(struct sys_device *sysdev) { ! drm_device_t *dev = (drm_device_t *)sysdev; DRM_DEBUG("%s\n", __FUNCTION__); --- 36,60 ---- #include <linux/device.h> #include <linux/sysdev.h> ! static int drm_suspend(struct sys_device *sysdev, pm_message_t state) { ! ! int event; ! ! drm_device_t *dev = ((drm_sysdev_t *) sysdev)->dev; ! event = state.event; + DRM_DEBUG("%s state=%d\n", __FUNCTION__, event); + if (dev->driver->power) ! return dev->driver->power(dev, event); else return 0; } static int drm_resume(struct sys_device *sysdev) { ! drm_device_t *dev = ((drm_sysdev_t *) sysdev)->dev; DRM_DEBUG("%s\n", __FUNCTION__); *************** *** 79,91 **** DRM_DEBUG("%s\n", __FUNCTION__); ! dev->sysdev.id = dev->primary.minor; ! dev->sysdev.cls = &drm_sysdev_class; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) ! error = sys_device_register(&dev->sysdev); #else ! error = sysdev_register(&dev->sysdev); #endif if(!error) dev->sysdev_registered = 1; --- 83,96 ---- DRM_DEBUG("%s\n", __FUNCTION__); ! dev->sysdev.sysdev.id = dev->primary.minor; ! dev->sysdev.sysdev.cls = &drm_sysdev_class; ! dev->sysdev.drmdev.dev = dev; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) ! error = sys_device_register(&dev->sysdev.sysdev); #else ! error = sysdev_register(&dev->sysdev.sysdev); #endif if(!error) dev->sysdev_registered = 1; *************** *** 103,111 **** if(dev->sysdev_registered) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) ! sys_device_unregister(&dev->sysdev); #else ! sysdev_unregister(&dev->sysdev); #endif dev->sysdev_registered = 0; } --- 108,116 ---- if(dev->sysdev_registered) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4) ! sys_device_unregister(&dev->sysdev.sysdev); #else ! sysdev_unregister(&dev->sysdev.sysdev); #endif dev->sysdev_registered = 0; } -- Configure bugmail: https://bugs.freedesktop.org/userprefs.cgi?tab=email ------- You are receiving this mail because: ------- You are the assignee for the bug, or are watching the assignee. ------------------------------------------------------- SF.Net email is sponsored by: Discover Easy Linux Migration Strategies from IBM. Find simple to follow Roadmaps, straightforward articles, informative Webcasts and more! Get everything you need to get up to speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click -- _______________________________________________ Dri-devel mailing list Dri-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/dri-devel