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: [email protected]
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
[email protected]
https://lists.sourceforge.net/lists/listinfo/dri-devel