aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm/omap_irq.c
blob: 9adfa7c99695f320e4bf8e0063e2605d2f0717c6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
/*
 * drivers/gpu/drm/omapdrm/omap_irq.c
 *
 * Copyright (C) 2012 Texas Instruments
 * Author: Rob Clark <rob.clark@linaro.org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "omap_drv.h"

struct omap_irq_wait {
	struct list_head node;
	wait_queue_head_t wq;
	uint32_t irqmask;
	int count;
};

/* call with wait_lock and dispc runtime held */
static void omap_irq_update(struct drm_device *dev)
{
	struct omap_drm_private *priv = dev->dev_private;
	struct omap_irq_wait *wait;
	uint32_t irqmask = priv->irq_mask;

	assert_spin_locked(&priv->wait_lock);

	list_for_each_entry(wait, &priv->wait_list, node)
		irqmask |= wait->irqmask;

	DBG("irqmask=%08x", irqmask);

	dispc_write_irqenable(irqmask);
	dispc_read_irqenable();        /* flush posted write */
}

static void omap_irq_wait_handler(struct omap_irq_wait *wait)
{
	wait->count--;
	wake_up(&wait->wq);
}

struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev,
		uint32_t irqmask, int count)
{
	struct omap_drm_private *priv = dev->dev_private;
	struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL);
	unsigned long flags;

	init_waitqueue_head(&wait->wq);
	wait->irqmask = irqmask;
	wait->count = count;

	spin_lock_irqsave(&priv->wait_lock, flags);
	list_add(&wait->node, &priv->wait_list);
	omap_irq_update(dev);
	spin_unlock_irqrestore(&priv->wait_lock, flags);

	return wait;
}

int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait,
		unsigned long timeout)
{
	struct omap_drm_private *priv = dev->dev_private;
	unsigned long flags;
	int ret;

	ret = wait_event_timeout(wait->wq, (wait->count <= 0), timeout);

	spin_lock_irqsave(&priv->wait_lock, flags);
	list_del(&wait->node);
	omap_irq_update(dev);
	spin_unlock_irqrestore(&priv->wait_lock, flags);

	kfree(wait);

	return ret == 0 ? -1 : 0;
}

/**
 * enable_vblank - enable vblank interrupt events
 * @dev: DRM device
 * @pipe: which irq to enable
 *
 * Enable vblank interrupts for @crtc.  If the device doesn't have
 * a hardware vblank counter, this routine should be a no-op, since
 * interrupts will have to stay on to keep the count accurate.
 *
 * RETURNS
 * Zero on success, appropriate errno if the given @crtc's vblank
 * interrupt cannot be enabled.
 */
int omap_irq_enable_vblank(struct drm_device *dev, unsigned int pipe)
{
	struct omap_drm_private *priv = dev->dev_private;
	struct drm_crtc *crtc = priv->crtcs[pipe];
	unsigned long flags;

	DBG("dev=%p, crtc=%u", dev, pipe);

	spin_lock_irqsave(&priv->wait_lock, flags);
	priv->irq_mask |= dispc_mgr_get_vsync_irq(omap_crtc_channel(crtc));
	omap_irq_update(dev);
	spin_unlock_irqrestore(&priv->wait_lock, flags);

	return 0;
}

/**
 * disable_vblank - disable vblank interrupt events
 * @dev: DRM device
 * @pipe: which irq to enable
 *
 * Disable vblank interrupts for @crtc.  If the device doesn't have
 * a hardware vblank counter, this routine should be a no-op, since
 * interrupts will have to stay on to keep the count accurate.
 */
void omap_irq_disable_vblank(struct drm_device *dev, unsigned int pipe)
{
	struct omap_drm_private *priv = dev->dev_private;
	struct drm_crtc *crtc = priv->crtcs[pipe];
	unsigned long flags;

	DBG("dev=%p, crtc=%u", dev, pipe);

	spin_lock_irqsave(&priv->wait_lock, flags);
	priv->irq_mask &= ~dispc_mgr_get_vsync_irq(omap_crtc_channel(crtc));
	omap_irq_update(dev);
	spin_unlock_irqrestore(&priv->wait_lock, flags);
}

static void omap_irq_fifo_underflow(struct omap_drm_private *priv,
				    u32 irqstatus)
{
	static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
				      DEFAULT_RATELIMIT_BURST);
	static const struct {
		const char *name;
		u32 mask;
	} sources[] = {
		{ "gfx", DISPC_IRQ_GFX_FIFO_UNDERFLOW },
		{ "vid1", DISPC_IRQ_VID1_FIFO_UNDERFLOW },
		{ "vid2", DISPC_IRQ_VID2_FIFO_UNDERFLOW },
		{ "vid3", DISPC_IRQ_VID3_FIFO_UNDERFLOW },
	};

	const u32 mask = DISPC_IRQ_GFX_FIFO_UNDERFLOW
		       | DISPC_IRQ_VID1_FIFO_UNDERFLOW
		       | DISPC_IRQ_VID2_FIFO_UNDERFLOW
		       | DISPC_IRQ_VID3_FIFO_UNDERFLOW;
	unsigned int i;

	spin_lock(&priv->wait_lock);
	irqstatus &= priv->irq_mask & mask;
	spin_unlock(&priv->wait_lock);

	if (!irqstatus)
		return;

	if (!__ratelimit(&_rs))
		return;

	DRM_ERROR("FIFO underflow on ");

	for (i = 0; i < ARRAY_SIZE(sources); ++i) {
		if (sources[i].mask & irqstatus)
			pr_cont("%s ", sources[i].name);
	}

	pr_cont("(0x%08x)\n", irqstatus);
}

static void omap_irq_ocp_error_handler(u32 irqstatus)
{
	if (!(irqstatus & DISPC_IRQ_OCP_ERR))
		return;

	DRM_ERROR("OCP error\n");
}

static irqreturn_t omap_irq_handler(int irq, void *arg)
{
	struct drm_device *dev = (struct drm_device *) arg;
	struct omap_drm_private *priv = dev->dev_private;
	struct omap_irq_wait *wait, *n;
	unsigned long flags;
	unsigned int id;
	u32 irqstatus;

	irqstatus = dispc_read_irqstatus();
	dispc_clear_irqstatus(irqstatus);
	dispc_read_irqstatus();        /* flush posted write */

	VERB("irqs: %08x", irqstatus);

	for (id = 0; id < priv->num_crtcs; id++) {
		struct drm_crtc *crtc = priv->crtcs[id];
		enum omap_channel channel = omap_crtc_channel(crtc);

		if (irqstatus & dispc_mgr_get_vsync_irq(channel)) {
			drm_handle_vblank(dev, id);
			omap_crtc_vblank_irq(crtc);
		}

		if (irqstatus & dispc_mgr_get_sync_lost_irq(channel))
			omap_crtc_error_irq(crtc, irqstatus);
	}

	omap_irq_ocp_error_handler(irqstatus);
	omap_irq_fifo_underflow(priv, irqstatus);

	spin_lock_irqsave(&priv->wait_lock, flags);
	list_for_each_entry_safe(wait, n, &priv->wait_list, node) {
		if (wait->irqmask & irqstatus)
			omap_irq_wait_handler(wait);
	}
	spin_unlock_irqrestore(&priv->wait_lock, flags);

	return IRQ_HANDLED;
}

static const u32 omap_underflow_irqs[] = {
	[OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
	[OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
	[OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
	[OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
};

/*
 * We need a special version, instead of just using drm_irq_install(),
 * because we need to register the irq via omapdss.  Once omapdss and
 * omapdrm are merged together we can assign the dispc hwmod data to
 * ourselves and drop these and just use drm_irq_{install,uninstall}()
 */

int omap_drm_irq_install(struct drm_device *dev)
{
	struct omap_drm_private *priv = dev->dev_private;
	unsigned int num_mgrs = dss_feat_get_num_mgrs();
	unsigned int max_planes;
	unsigned int i;
	int ret;

	spin_lock_init(&priv->wait_lock);
	INIT_LIST_HEAD(&priv->wait_list);

	priv->irq_mask = DISPC_IRQ_OCP_ERR;

	max_planes = min(ARRAY_SIZE(priv->planes),
			 ARRAY_SIZE(omap_underflow_irqs));
	for (i = 0; i < max_planes; ++i) {
		if (priv->planes[i])
			priv->irq_mask |= omap_underflow_irqs[i];
	}

	for (i = 0; i < num_mgrs; ++i)
		priv->irq_mask |= dispc_mgr_get_sync_lost_irq(i);

	dispc_runtime_get();
	dispc_clear_irqstatus(0xffffffff);
	dispc_runtime_put();

	ret = dispc_request_irq(omap_irq_handler, dev);
	if (ret < 0)
		return ret;

	dev->irq_enabled = true;

	return 0;
}

void omap_drm_irq_uninstall(struct drm_device *dev)
{
	unsigned long irqflags;
	int i;

	if (!dev->irq_enabled)
		return;

	dev->irq_enabled = false;

	/* Wake up any waiters so they don't hang. */
	if (dev->num_crtcs) {
		spin_lock_irqsave(&dev->vbl_lock, irqflags);
		for (i = 0; i < dev->num_crtcs; i++) {
			wake_up(&dev->vblank[i].queue);
			dev->vblank[i].enabled = false;
			dev->vblank[i].last =
				dev->driver->get_vblank_counter(dev, i);
		}
		spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
	}

	dispc_free_irq(dev);
}
obox.com> 2012-01-06Git 1.7.9-rc0v1.7.9-rc0Junio C Hamano2-1/+8 Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-06Git 1.7.8.3v1.7.8.3Junio C Hamano4-3/+22 Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-06Documentation: rerere.enabled is the primary way to configure rerereThomas Rast1-4/+4 The wording seems to suggest that creating the directory is needed and the setting of rerere.enabled is only for disabling the feature by setting it to 'false'. But the configuration is meant to be the primary control and setting it to 'true' will enable it; the rr-cache directory will be created as necessary and the user does not have to create it. Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-06write_head_info(): handle "extra refs" locallyMichael Haggerty1-4/+3 The old code basically did: generate array of SHA1s for alternate refs for each unique SHA1 in array: add_extra_ref(".have", sha1) for each ref (including real refs and extra refs): show_ref(refname, sha1) But there is no need to stuff the alternate refs in extra_refs; we can call show_ref() directly when iterating over the array, then handle real refs separately. So change the code to: generate array of SHA1s for alternate refs for each unique SHA1 in array: show_ref(".have", sha1) for each ref (this now only includes real refs): show_ref(refname, sha1) Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-06show_ref(): remove unused "flag" and "cb_data" argumentsMichael Haggerty1-5/+5 The function is not used as a callback, so it doesn't need these arguments. Also change its return type to void. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-06receive-pack: move more work into write_head_info()Michael Haggerty1-24/+18 Move some more code from the calling site into write_head_info(), and inline add_alternate_refs() there. (Some more simplification is coming, and it is easier if all this code is in the same place.) Move some helper functions to avoid the need for forward declarations. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-05log --show-signature: reword the common two-head merge caseJunio C Hamano1-0/+12 While identifying the commit merged to our history as "parent #2" is technically correct, we will never say "parent #1" (as that is the tip of our history before the merge is made), and we rarely would say "parent #3" (which would mean the merge is an octopus), especially when responding to a request to pull a signed tag. Treat the most common case to merge a single commit specially, and just say "merged tag '<tagname>'" instead. Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-05log-tree: show mergetag in log --show-signature outputJunio C Hamano1-1/+75 A commit object that merges a signed tag records the "mergetag" extended header. Check the validity of the GPG signature on it, and show it in a way similar to how "gpgsig" extended header is shown. Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-05log-tree.c: small refactor in show_signature()Junio C Hamano1-12/+16 The next patch needs to show the result of signature verification on a mergetag extended header in a way similar to how embedded signature for the commit object itself is shown. Separate out the logic to go through the message lines and show them in the "error" color (highlighted) or the "correct" color (dim). Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-05commit --amend -S: strip existing gpgsig headersJunio C Hamano4-8/+36 Any existing commit signature was made against the contents of the old commit, including its committer date that is about to change, and will become invalid by amending it. Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-05verify_signed_buffer: fix stale commentJunio C Hamano1-4/+1 The function used to take an integer flag to specify where the output should go, but these days we supply a strbuf to receive it. Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-04t5550: repack everything into one fileClemens Buchacher1-2/+1 Subsequently we assume that there is only one pack. Currently this is true only by accident. Pass '-a -d' to repack in order to guarantee that assumption to hold true. The prune-packed command is now redundant since repack -d already calls it. Signed-off-by: Clemens Buchacher <drizzd@aon.at> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-04gitweb: accept trailing "/" in $project_listMatthieu Moy1-2/+2 The current code is removing the trailing "/", but computing the string length on the previous value, i.e. with the trailing "/". Later in the code, we do my $path = substr($File::Find::name, $pfxlen + 1); And the "$pfxlen + 1" is supposed to mean "the length of the prefix, plus 1 for the / separating the prefix and the path", but with an incorrect $pfxlen, this basically eats the first character of the path, and yields "404 - No projects found". While we're there, also fix $pfxdepth to use $dir, although a change of 1 in the depth shouldn't really matter. Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-04Catch invalid --depth option passed to clone or fetchNguyễn Thái Ngọc Duy1-2/+6 Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-03write first for-merge ref to FETCH_HEAD firstJoey Hess25-102/+114 The FETCH_HEAD refname is supposed to refer to the ref that was fetched and should be merged. However all fetched refs are written to .git/FETCH_HEAD in an arbitrary order, and resolve_ref_unsafe simply takes the first ref as the FETCH_HEAD, which is often the wrong one, when other branches were also fetched. The solution is to write the for-merge ref(s) to FETCH_HEAD first. Then, unless --append is used, the FETCH_HEAD refname behaves as intended. If the user uses --append, they presumably are doing so in order to preserve the old FETCH_HEAD. While we are at it, update an old example in the read-tree documentation that implied that each entry in FETCH_HEAD only has the object name, which is not true for quite a while. [jc: adjusted tests] Signed-off-by: Joey Hess <joey@kitenet.net> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-03git-p4: view spec documentationPete Wyckoff1-13/+27 Signed-off-by: Pete Wyckoff <pw@padd.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-03git-p4: rewrite view handlingPete Wyckoff2-101/+258 The old code was not very complete or robust. Redo it. This new code should be useful for a few possible additions in the future: - support for * and %%n wildcards - allowing ... inside paths - representing branch specs (not just client specs) - tracking changes to views Mark the remaining 12 tests in t9809 as fixed. Signed-off-by: Pete Wyckoff <pw@padd.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-03git-p4: support single file p4 client view mapsGary Gibbons2-10/+21 Perforce client views can map individual files, mapping one //depot file path to one //client file path. These mappings contain no meta/masking characters. This patch add support for these file maps to the currently supported '...' view mappings. [pw: one test now suceeds] Signed-off-by: Gary Gibbons <ggibbons@perforce.com> Signed-off-by: Pete Wyckoff <pw@padd.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-03git-p4: sort client views by reverse View numberGary Gibbons2-3/+10 Correct view sorting to support the Perforce order, where client views are ordered and later views override earlier view mappings. [pw: one test now succeeds] Signed-off-by: Gary Gibbons <ggibbons@perforce.com> Signed-off-by: Pete Wyckoff <pw@padd.com> Signed-off-by: Junio C Hamano <gitster@pobox.com> 2012-01-03git-p4: fix test for unsupported P4 Client ViewsGary Gibbons2-3/+6 Change re method in test for unsupported Client View types (containing %% or *) anywhere in the string rather than at the begining. [pw: two tests now succeed] Signed-off-by: Gary Gibbons <ggibbons@perforce.com> Signed-off-by: Pete Wyckoff <pw@padd.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>