Subversion Repositories Kolibri OS

Rev

Rev 6935 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5060 serge 1
/*
2
 * drm_irq.c IRQ and vblank support
1963 serge 3
 *
4
 * \author Rickard E. (Rik) Faith 
5
 * \author Gareth Hughes 
6
 */
7
 
8
/*
9
 * Created: Fri Mar 19 14:30:16 1999 by faith@valinux.com
10
 *
11
 * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas.
12
 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
13
 * All Rights Reserved.
14
 *
15
 * Permission is hereby granted, free of charge, to any person obtaining a
16
 * copy of this software and associated documentation files (the "Software"),
17
 * to deal in the Software without restriction, including without limitation
18
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19
 * and/or sell copies of the Software, and to permit persons to whom the
20
 * Software is furnished to do so, subject to the following conditions:
21
 *
22
 * The above copyright notice and this permission notice (including the next
23
 * paragraph) shall be included in all copies or substantial portions of the
24
 * Software.
25
 *
26
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
29
 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
30
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
31
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
32
 * OTHER DEALINGS IN THE SOFTWARE.
33
 */
34
 
3031 serge 35
#include 
1963 serge 36
//#include "drm_trace.h"
5271 serge 37
#include "drm_internal.h"
1963 serge 38
 
6935 serge 39
#include 	/* For task queue support */
1963 serge 40
#include 
41
 
5271 serge 42
#include 
3031 serge 43
#include 
1963 serge 44
 
6084 serge 45
ktime_t ktime_get(void);
46
 
47
static inline ktime_t ktime_get_real(void)
48
{
49
	return ktime_get();
50
}
51
 
52
static inline ktime_t ktime_mono_to_real(ktime_t mono)
53
{
54
	return mono;
55
}
56
 
6131 serge 57
irqreturn_t device_irq_handler(struct drm_device *dev)
58
{
59
	return dev->driver->irq_handler(0, dev);
60
}
6084 serge 61
 
1963 serge 62
/* Access macro for slots in vblank timestamp ringbuffer. */
6084 serge 63
#define vblanktimestamp(dev, pipe, count) \
64
	((dev)->vblank[pipe].time[(count) % DRM_VBLANKTIME_RBSIZE])
1963 serge 65
 
66
/* Retry timestamp calculation up to 3 times to satisfy
67
 * drm_timestamp_precision before giving up.
68
 */
69
#define DRM_TIMESTAMP_MAXRETRIES 3
70
 
71
/* Threshold in nanoseconds for detection of redundant
72
 * vblank irq in drm_handle_vblank(). 1 msec should be ok.
73
 */
74
#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000
75
 
5271 serge 76
static bool
6084 serge 77
drm_get_last_vbltimestamp(struct drm_device *dev, unsigned int pipe,
5271 serge 78
			  struct timeval *tvblank, unsigned flags);
79
 
80
static unsigned int drm_timestamp_precision = 20;  /* Default to 20 usecs. */
81
 
5060 serge 82
/*
6084 serge 83
 * Default to use monotonic timestamps for wait-for-vblank and page-flip
84
 * complete events.
5060 serge 85
 */
6084 serge 86
unsigned int drm_timestamp_monotonic = 1;
1963 serge 87
 
6084 serge 88
static int drm_vblank_offdelay = 5000;    /* Default to 5000 msecs. */
5060 serge 89
 
6084 serge 90
module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
91
module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
92
module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
93
 
94
static void store_vblank(struct drm_device *dev, unsigned int pipe,
95
			 u32 vblank_count_inc,
96
			 struct timeval *t_vblank, u32 last)
97
{
98
	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
99
	u32 tslot;
100
 
101
	assert_spin_locked(&dev->vblank_time_lock);
102
 
103
	vblank->last = last;
104
 
105
	/* All writers hold the spinlock, but readers are serialized by
106
	 * the latching of vblank->count below.
107
	 */
108
	tslot = vblank->count + vblank_count_inc;
109
	vblanktimestamp(dev, pipe, tslot) = *t_vblank;
110
 
111
	/*
112
	 * vblank timestamp updates are protected on the write side with
113
	 * vblank_time_lock, but on the read side done locklessly using a
114
	 * sequence-lock on the vblank counter. Ensure correct ordering using
115
	 * memory barrriers. We need the barrier both before and also after the
116
	 * counter update to synchronize with the next timestamp write.
117
	 * The read-side barriers for this are in drm_vblank_count_and_time.
118
	 */
119
	smp_wmb();
120
	vblank->count += vblank_count_inc;
121
	smp_wmb();
122
}
123
 
5060 serge 124
/**
6084 serge 125
 * drm_reset_vblank_timestamp - reset the last timestamp to the last vblank
126
 * @dev: DRM device
127
 * @pipe: index of CRTC for which to reset the timestamp
128
 *
129
 * Reset the stored timestamp for the current vblank count to correspond
130
 * to the last vblank occurred.
131
 *
132
 * Only to be called from drm_vblank_on().
133
 *
134
 * Note: caller must hold dev->vbl_lock since this reads & writes
135
 * device vblank fields.
136
 */
137
static void drm_reset_vblank_timestamp(struct drm_device *dev, unsigned int pipe)
138
{
139
	u32 cur_vblank;
140
	bool rc;
141
	struct timeval t_vblank;
142
	int count = DRM_TIMESTAMP_MAXRETRIES;
143
 
144
	spin_lock(&dev->vblank_time_lock);
145
 
146
	/*
147
	 * sample the current counter to avoid random jumps
148
	 * when drm_vblank_enable() applies the diff
149
	 */
150
	do {
151
		cur_vblank = dev->driver->get_vblank_counter(dev, pipe);
152
		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, 0);
153
	} while (cur_vblank != dev->driver->get_vblank_counter(dev, pipe) && --count > 0);
154
 
155
	/*
156
	 * Only reinitialize corresponding vblank timestamp if high-precision query
157
	 * available and didn't fail. Otherwise reinitialize delayed at next vblank
158
	 * interrupt and assign 0 for now, to mark the vblanktimestamp as invalid.
159
	 */
160
	if (!rc)
161
		t_vblank = (struct timeval) {0, 0};
162
 
163
	/*
164
	 * +1 to make sure user will never see the same
165
	 * vblank counter value before and after a modeset
166
	 */
167
	store_vblank(dev, pipe, 1, &t_vblank, cur_vblank);
168
 
169
	spin_unlock(&dev->vblank_time_lock);
170
}
171
 
172
/**
173
 * drm_update_vblank_count - update the master vblank counter
174
 * @dev: DRM device
175
 * @pipe: counter to update
176
 *
177
 * Call back into the driver to update the appropriate vblank counter
178
 * (specified by @pipe).  Deal with wraparound, if it occurred, and
179
 * update the last read value so we can deal with wraparound on the next
180
 * call if necessary.
181
 *
182
 * Only necessary when going from off->on, to account for frames we
183
 * didn't get an interrupt for.
184
 *
185
 * Note: caller must hold dev->vbl_lock since this reads & writes
186
 * device vblank fields.
187
 */
188
static void drm_update_vblank_count(struct drm_device *dev, unsigned int pipe,
189
				    unsigned long flags)
190
{
191
	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
192
	u32 cur_vblank, diff;
193
	bool rc;
194
	struct timeval t_vblank;
195
	int count = DRM_TIMESTAMP_MAXRETRIES;
196
	int framedur_ns = vblank->framedur_ns;
197
 
198
	/*
199
	 * Interrupts were disabled prior to this call, so deal with counter
200
	 * wrap if needed.
201
	 * NOTE!  It's possible we lost a full dev->max_vblank_count + 1 events
202
	 * here if the register is small or we had vblank interrupts off for
203
	 * a long time.
204
	 *
205
	 * We repeat the hardware vblank counter & timestamp query until
206
	 * we get consistent results. This to prevent races between gpu
207
	 * updating its hardware counter while we are retrieving the
208
	 * corresponding vblank timestamp.
209
	 */
210
	do {
211
		cur_vblank = dev->driver->get_vblank_counter(dev, pipe);
212
		rc = drm_get_last_vbltimestamp(dev, pipe, &t_vblank, flags);
213
	} while (cur_vblank != dev->driver->get_vblank_counter(dev, pipe) && --count > 0);
214
 
215
	if (dev->max_vblank_count != 0) {
216
		/* trust the hw counter when it's around */
217
		diff = (cur_vblank - vblank->last) & dev->max_vblank_count;
218
	} else if (rc && framedur_ns) {
219
		const struct timeval *t_old;
220
		u64 diff_ns;
221
 
222
		t_old = &vblanktimestamp(dev, pipe, vblank->count);
223
		diff_ns = timeval_to_ns(&t_vblank) - timeval_to_ns(t_old);
224
 
225
		/*
226
		 * Figure out how many vblanks we've missed based
227
		 * on the difference in the timestamps and the
228
		 * frame/field duration.
229
		 */
230
		diff = DIV_ROUND_CLOSEST_ULL(diff_ns, framedur_ns);
231
 
232
		if (diff == 0 && flags & DRM_CALLED_FROM_VBLIRQ)
233
			DRM_DEBUG_VBL("crtc %u: Redundant vblirq ignored."
234
				      " diff_ns = %lld, framedur_ns = %d)\n",
235
				      pipe, (long long) diff_ns, framedur_ns);
236
	} else {
237
		/* some kind of default for drivers w/o accurate vbl timestamping */
238
		diff = (flags & DRM_CALLED_FROM_VBLIRQ) != 0;
239
	}
240
 
6320 serge 241
	/*
242
	 * Within a drm_vblank_pre_modeset - drm_vblank_post_modeset
243
	 * interval? If so then vblank irqs keep running and it will likely