Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
2e54a007
Commit
2e54a007
authored
Oct 24, 2006
by
=?utf-8?q?Michel_D=C3=A4nzer?=
Committed by
airlied
Dec 07, 2006
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
drm: Add support for interrupt triggered driver callback with lock held to DRM core.
Signed-off-by:
Dave Airlie
<
airlied@linux.ie
>
parent
bea5679f
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
90 additions
and
0 deletions
+90
-0
drivers/char/drm/drmP.h
drivers/char/drm/drmP.h
+3
-0
drivers/char/drm/drm_irq.c
drivers/char/drm/drm_irq.c
+76
-0
drivers/char/drm/drm_lock.c
drivers/char/drm/drm_lock.c
+11
-0
No files found.
drivers/char/drm/drmP.h
View file @
2e54a007
...
...
@@ -715,6 +715,8 @@ typedef struct drm_device {
drm_vbl_sig_t
vbl_sigs
;
/**< signal list to send on VBLANK */
drm_vbl_sig_t
vbl_sigs2
;
/**< signals to send on secondary VBLANK */
unsigned
int
vbl_pending
;
spinlock_t
tasklet_lock
;
/**< For drm_locked_tasklet */
void
(
*
locked_tasklet_func
)(
struct
drm_device
*
dev
);
/*@} */
cycles_t
ctx_start
;
...
...
@@ -966,6 +968,7 @@ extern int drm_wait_vblank(struct inode *inode, struct file *filp,
unsigned
int
cmd
,
unsigned
long
arg
);
extern
int
drm_vblank_wait
(
drm_device_t
*
dev
,
unsigned
int
*
vbl_seq
);
extern
void
drm_vbl_send_signals
(
drm_device_t
*
dev
);
extern
void
drm_locked_tasklet
(
drm_device_t
*
dev
,
void
(
*
func
)(
drm_device_t
*
));
/* AGP/GART support (drm_agpsupport.h) */
extern
drm_agp_head_t
*
drm_agp_init
(
drm_device_t
*
dev
);
...
...
drivers/char/drm/drm_irq.c
View file @
2e54a007
...
...
@@ -119,6 +119,7 @@ static int drm_irq_install(drm_device_t * dev)
init_waitqueue_head
(
&
dev
->
vbl_queue
);
spin_lock_init
(
&
dev
->
vbl_lock
);
spin_lock_init
(
&
dev
->
tasklet_lock
);
INIT_LIST_HEAD
(
&
dev
->
vbl_sigs
.
head
);
INIT_LIST_HEAD
(
&
dev
->
vbl_sigs2
.
head
);
...
...
@@ -176,6 +177,8 @@ int drm_irq_uninstall(drm_device_t * dev)
free_irq
(
dev
->
irq
,
dev
);
dev
->
locked_tasklet_func
=
NULL
;
return
0
;
}
...
...
@@ -399,3 +402,76 @@ void drm_vbl_send_signals(drm_device_t * dev)
}
EXPORT_SYMBOL
(
drm_vbl_send_signals
);
/**
* Tasklet wrapper function.
*
* \param data DRM device in disguise.
*
* Attempts to grab the HW lock and calls the driver callback on success. On
* failure, leave the lock marked as contended so the callback can be called
* from drm_unlock().
*/
static
void
drm_locked_tasklet_func
(
unsigned
long
data
)
{
drm_device_t
*
dev
=
(
drm_device_t
*
)
data
;
unsigned
long
irqflags
;
spin_lock_irqsave
(
&
dev
->
tasklet_lock
,
irqflags
);
if
(
!
dev
->
locked_tasklet_func
||
!
drm_lock_take
(
&
dev
->
lock
.
hw_lock
->
lock
,
DRM_KERNEL_CONTEXT
))
{
spin_unlock_irqrestore
(
&
dev
->
tasklet_lock
,
irqflags
);
return
;
}
dev
->
lock
.
lock_time
=
jiffies
;
atomic_inc
(
&
dev
->
counts
[
_DRM_STAT_LOCKS
]);
dev
->
locked_tasklet_func
(
dev
);
drm_lock_free
(
dev
,
&
dev
->
lock
.
hw_lock
->
lock
,
DRM_KERNEL_CONTEXT
);
dev
->
locked_tasklet_func
=
NULL
;
spin_unlock_irqrestore
(
&
dev
->
tasklet_lock
,
irqflags
);
}
/**
* Schedule a tasklet to call back a driver hook with the HW lock held.
*
* \param dev DRM device.
* \param func Driver callback.
*
* This is intended for triggering actions that require the HW lock from an
* interrupt handler. The lock will be grabbed ASAP after the interrupt handler
* completes. Note that the callback may be called from interrupt or process
* context, it must not make any assumptions about this. Also, the HW lock will
* be held with the kernel context or any client context.
*/
void
drm_locked_tasklet
(
drm_device_t
*
dev
,
void
(
*
func
)(
drm_device_t
*
))
{
unsigned
long
irqflags
;
static
DECLARE_TASKLET
(
drm_tasklet
,
drm_locked_tasklet_func
,
0
);
if
(
test_bit
(
TASKLET_STATE_SCHED
,
&
drm_tasklet
.
state
))
return
;
spin_lock_irqsave
(
&
dev
->
tasklet_lock
,
irqflags
);
if
(
dev
->
locked_tasklet_func
)
{
spin_unlock_irqrestore
(
&
dev
->
tasklet_lock
,
irqflags
);
return
;
}
dev
->
locked_tasklet_func
=
func
;
spin_unlock_irqrestore
(
&
dev
->
tasklet_lock
,
irqflags
);
drm_tasklet
.
data
=
(
unsigned
long
)
dev
;
tasklet_hi_schedule
(
&
drm_tasklet
);
}
EXPORT_SYMBOL
(
drm_locked_tasklet
);
drivers/char/drm/drm_lock.c
View file @
2e54a007
...
...
@@ -155,6 +155,7 @@ int drm_unlock(struct inode *inode, struct file *filp,
drm_file_t
*
priv
=
filp
->
private_data
;
drm_device_t
*
dev
=
priv
->
head
->
dev
;
drm_lock_t
lock
;
unsigned
int
irqflags
;
if
(
copy_from_user
(
&
lock
,
(
drm_lock_t
__user
*
)
arg
,
sizeof
(
lock
)))
return
-
EFAULT
;
...
...
@@ -165,6 +166,16 @@ int drm_unlock(struct inode *inode, struct file *filp,
return
-
EINVAL
;
}
spin_lock_irqsave
(
&
dev
->
tasklet_lock
,
irqflags
);
if
(
dev
->
locked_tasklet_func
)
{
dev
->
locked_tasklet_func
(
dev
);
dev
->
locked_tasklet_func
=
NULL
;
}
spin_unlock_irqrestore
(
&
dev
->
tasklet_lock
,
irqflags
);
atomic_inc
(
&
dev
->
counts
[
_DRM_STAT_UNLOCKS
]);
/* kernel_context_switch isn't used by any of the x86 drm
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment