xref: /openbmc/linux/sound/pci/ctxfi/cttimer.c (revision ba61bb17)
1 /*
2  * PCM timer handling on ctxfi
3  *
4  * This source file is released under GPL v2 license (no other versions).
5  * See the COPYING file included in the main directory of this source
6  * distribution for the license terms and conditions.
7  */
8 
9 #include <linux/slab.h>
10 #include <linux/math64.h>
11 #include <linux/moduleparam.h>
12 #include <sound/core.h>
13 #include <sound/pcm.h>
14 #include "ctatc.h"
15 #include "cthardware.h"
16 #include "cttimer.h"
17 
18 static bool use_system_timer;
19 MODULE_PARM_DESC(use_system_timer, "Force to use system-timer");
20 module_param(use_system_timer, bool, 0444);
21 
22 struct ct_timer_ops {
23 	void (*init)(struct ct_timer_instance *);
24 	void (*prepare)(struct ct_timer_instance *);
25 	void (*start)(struct ct_timer_instance *);
26 	void (*stop)(struct ct_timer_instance *);
27 	void (*free_instance)(struct ct_timer_instance *);
28 	void (*interrupt)(struct ct_timer *);
29 	void (*free_global)(struct ct_timer *);
30 };
31 
32 /* timer instance -- assigned to each PCM stream */
33 struct ct_timer_instance {
34 	spinlock_t lock;
35 	struct ct_timer *timer_base;
36 	struct ct_atc_pcm *apcm;
37 	struct snd_pcm_substream *substream;
38 	struct timer_list timer;
39 	struct list_head instance_list;
40 	struct list_head running_list;
41 	unsigned int position;
42 	unsigned int frag_count;
43 	unsigned int running:1;
44 	unsigned int need_update:1;
45 };
46 
47 /* timer instance manager */
48 struct ct_timer {
49 	spinlock_t lock;		/* global timer lock (for xfitimer) */
50 	spinlock_t list_lock;		/* lock for instance list */
51 	struct ct_atc *atc;
52 	const struct ct_timer_ops *ops;
53 	struct list_head instance_head;
54 	struct list_head running_head;
55 	unsigned int wc;		/* current wallclock */
56 	unsigned int irq_handling:1;	/* in IRQ handling */
57 	unsigned int reprogram:1;	/* need to reprogram the internval */
58 	unsigned int running:1;		/* global timer running */
59 };
60 
61 
62 /*
63  * system-timer-based updates
64  */
65 
66 static void ct_systimer_callback(struct timer_list *t)
67 {
68 	struct ct_timer_instance *ti = from_timer(ti, t, timer);
69 	struct snd_pcm_substream *substream = ti->substream;
70 	struct snd_pcm_runtime *runtime = substream->runtime;
71 	struct ct_atc_pcm *apcm = ti->apcm;
72 	unsigned int period_size = runtime->period_size;
73 	unsigned int buffer_size = runtime->buffer_size;
74 	unsigned long flags;
75 	unsigned int position, dist, interval;
76 
77 	position = substream->ops->pointer(substream);
78 	dist = (position + buffer_size - ti->position) % buffer_size;
79 	if (dist >= period_size ||
80 	    position / period_size != ti->position / period_size) {
81 		apcm->interrupt(apcm);
82 		ti->position = position;
83 	}
84 	/* Add extra HZ*5/1000 to avoid overrun issue when recording
85 	 * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
86 	interval = ((period_size - (position % period_size))
87 		   * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000;
88 	spin_lock_irqsave(&ti->lock, flags);
89 	if (ti->running)
90 		mod_timer(&ti->timer, jiffies + interval);
91 	spin_unlock_irqrestore(&ti->lock, flags);
92 }
93 
94 static void ct_systimer_init(struct ct_timer_instance *ti)
95 {
96 	timer_setup(&ti->timer, ct_systimer_callback, 0);
97 }
98 
99 static void ct_systimer_start(struct ct_timer_instance *ti)
100 {
101 	struct snd_pcm_runtime *runtime = ti->substream->runtime;
102 	unsigned long flags;
103 
104 	spin_lock_irqsave(&ti->lock, flags);
105 	ti->running = 1;
106 	mod_timer(&ti->timer,
107 		  jiffies + (runtime->period_size * HZ +
108 			     (runtime->rate - 1)) / runtime->rate);
109 	spin_unlock_irqrestore(&ti->lock, flags);
110 }
111 
112 static void ct_systimer_stop(struct ct_timer_instance *ti)
113 {
114 	unsigned long flags;
115 
116 	spin_lock_irqsave(&ti->lock, flags);
117 	ti->running = 0;
118 	del_timer(&ti->timer);
119 	spin_unlock_irqrestore(&ti->lock, flags);
120 }
121 
122 static void ct_systimer_prepare(struct ct_timer_instance *ti)
123 {
124 	ct_systimer_stop(ti);
125 	try_to_del_timer_sync(&ti->timer);
126 }
127 
128 #define ct_systimer_free	ct_systimer_prepare
129 
130 static const struct ct_timer_ops ct_systimer_ops = {
131 	.init = ct_systimer_init,
132 	.free_instance = ct_systimer_free,
133 	.prepare = ct_systimer_prepare,
134 	.start = ct_systimer_start,
135 	.stop = ct_systimer_stop,
136 };
137 
138 
139 /*
140  * Handling multiple streams using a global emu20k1 timer irq
141  */
142 
143 #define CT_TIMER_FREQ	48000
144 #define MIN_TICKS	1
145 #define MAX_TICKS	((1 << 13) - 1)
146 
147 static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks)
148 {
149 	struct hw *hw = atimer->atc->hw;
150 	if (ticks > MAX_TICKS)
151 		ticks = MAX_TICKS;
152 	hw->set_timer_tick(hw, ticks);
153 	if (!atimer->running)
154 		hw->set_timer_irq(hw, 1);
155 	atimer->running = 1;
156 }
157 
158 static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
159 {
160 	if (atimer->running) {
161 		struct hw *hw = atimer->atc->hw;
162 		hw->set_timer_irq(hw, 0);
163 		hw->set_timer_tick(hw, 0);
164 		atimer->running = 0;
165 	}
166 }
167 
168 static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
169 {
170 	struct hw *hw = atimer->atc->hw;
171 	return hw->get_wc(hw);
172 }
173 
174 /*
175  * reprogram the timer interval;
176  * checks the running instance list and determines the next timer interval.
177  * also updates the each stream position, returns the number of streams
178  * to call snd_pcm_period_elapsed() appropriately
179  *
180  * call this inside the lock and irq disabled
181  */
182 static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update)
183 {
184 	struct ct_timer_instance *ti;
185 	unsigned int min_intr = (unsigned int)-1;
186 	int updates = 0;
187 	unsigned int wc, diff;
188 
189 	if (list_empty(&atimer->running_head)) {
190 		ct_xfitimer_irq_stop(atimer);
191 		atimer->reprogram = 0; /* clear flag */
192 		return 0;
193 	}
194 
195 	wc = ct_xfitimer_get_wc(atimer);
196 	diff = wc - atimer->wc;
197 	atimer->wc = wc;
198 	list_for_each_entry(ti, &atimer->running_head, running_list) {
199 		if (ti->frag_count > diff)
200 			ti->frag_count -= diff;
201 		else {
202 			unsigned int pos;
203 			unsigned int period_size, rate;
204 
205 			period_size = ti->substream->runtime->period_size;
206 			rate = ti->substream->runtime->rate;
207 			pos = ti->substream->ops->pointer(ti->substream);
208 			if (pos / period_size != ti->position / period_size) {
209 				ti->need_update = 1;
210 				ti->position = pos;
211 				updates++;
212 			}
213 			pos %= period_size;
214 			pos = period_size - pos;
215 			ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
216 						 rate - 1, rate);
217 		}
218 		if (ti->need_update && !can_update)
219 			min_intr = 0; /* pending to the next irq */
220 		if (ti->frag_count < min_intr)
221 			min_intr = ti->frag_count;
222 	}
223 
224 	if (min_intr < MIN_TICKS)
225 		min_intr = MIN_TICKS;
226 	ct_xfitimer_irq_rearm(atimer, min_intr);
227 	atimer->reprogram = 0; /* clear flag */
228 	return updates;
229 }
230 
231 /* look through the instance list and call period_elapsed if needed */
232 static void ct_xfitimer_check_period(struct ct_timer *atimer)
233 {
234 	struct ct_timer_instance *ti;
235 	unsigned long flags;
236 
237 	spin_lock_irqsave(&atimer->list_lock, flags);
238 	list_for_each_entry(ti, &atimer->instance_head, instance_list) {
239 		if (ti->running && ti->need_update) {
240 			ti->need_update = 0;
241 			ti->apcm->interrupt(ti->apcm);
242 		}
243 	}
244 	spin_unlock_irqrestore(&atimer->list_lock, flags);
245 }
246 
247 /* Handle timer-interrupt */
248 static void ct_xfitimer_callback(struct ct_timer *atimer)
249 {
250 	int update;
251 	unsigned long flags;
252 
253 	spin_lock_irqsave(&atimer->lock, flags);
254 	atimer->irq_handling = 1;
255 	do {
256 		update = ct_xfitimer_reprogram(atimer, 1);
257 		spin_unlock(&atimer->lock);
258 		if (update)
259 			ct_xfitimer_check_period(atimer);
260 		spin_lock(&atimer->lock);
261 	} while (atimer->reprogram);
262 	atimer->irq_handling = 0;
263 	spin_unlock_irqrestore(&atimer->lock, flags);
264 }
265 
266 static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
267 {
268 	ti->frag_count = ti->substream->runtime->period_size;
269 	ti->running = 0;
270 	ti->need_update = 0;
271 }
272 
273 
274 /* start/stop the timer */
275 static void ct_xfitimer_update(struct ct_timer *atimer)
276 {
277 	unsigned long flags;
278 
279 	spin_lock_irqsave(&atimer->lock, flags);
280 	if (atimer->irq_handling) {
281 		/* reached from IRQ handler; let it handle later */
282 		atimer->reprogram = 1;
283 		spin_unlock_irqrestore(&atimer->lock, flags);
284 		return;
285 	}
286 
287 	ct_xfitimer_irq_stop(atimer);
288 	ct_xfitimer_reprogram(atimer, 0);
289 	spin_unlock_irqrestore(&atimer->lock, flags);
290 }
291 
292 static void ct_xfitimer_start(struct ct_timer_instance *ti)
293 {
294 	struct ct_timer *atimer = ti->timer_base;
295 	unsigned long flags;
296 
297 	spin_lock_irqsave(&atimer->lock, flags);
298 	if (list_empty(&ti->running_list))
299 		atimer->wc = ct_xfitimer_get_wc(atimer);
300 	ti->running = 1;
301 	ti->need_update = 0;
302 	list_add(&ti->running_list, &atimer->running_head);
303 	spin_unlock_irqrestore(&atimer->lock, flags);
304 	ct_xfitimer_update(atimer);
305 }
306 
307 static void ct_xfitimer_stop(struct ct_timer_instance *ti)
308 {
309 	struct ct_timer *atimer = ti->timer_base;
310 	unsigned long flags;
311 
312 	spin_lock_irqsave(&atimer->lock, flags);
313 	list_del_init(&ti->running_list);
314 	ti->running = 0;
315 	spin_unlock_irqrestore(&atimer->lock, flags);
316 	ct_xfitimer_update(atimer);
317 }
318 
319 static void ct_xfitimer_free_global(struct ct_timer *atimer)
320 {
321 	ct_xfitimer_irq_stop(atimer);
322 }
323 
324 static const struct ct_timer_ops ct_xfitimer_ops = {
325 	.prepare = ct_xfitimer_prepare,
326 	.start = ct_xfitimer_start,
327 	.stop = ct_xfitimer_stop,
328 	.interrupt = ct_xfitimer_callback,
329 	.free_global = ct_xfitimer_free_global,
330 };
331 
332 /*
333  * timer instance
334  */
335 
336 struct ct_timer_instance *
337 ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm)
338 {
339 	struct ct_timer_instance *ti;
340 
341 	ti = kzalloc(sizeof(*ti), GFP_KERNEL);
342 	if (!ti)
343 		return NULL;
344 	spin_lock_init(&ti->lock);
345 	INIT_LIST_HEAD(&ti->instance_list);
346 	INIT_LIST_HEAD(&ti->running_list);
347 	ti->timer_base = atimer;
348 	ti->apcm = apcm;
349 	ti->substream = apcm->substream;
350 	if (atimer->ops->init)
351 		atimer->ops->init(ti);
352 
353 	spin_lock_irq(&atimer->list_lock);
354 	list_add(&ti->instance_list, &atimer->instance_head);
355 	spin_unlock_irq(&atimer->list_lock);
356 
357 	return ti;
358 }
359 
360 void ct_timer_prepare(struct ct_timer_instance *ti)
361 {
362 	if (ti->timer_base->ops->prepare)
363 		ti->timer_base->ops->prepare(ti);
364 	ti->position = 0;
365 	ti->running = 0;
366 }
367 
368 void ct_timer_start(struct ct_timer_instance *ti)
369 {
370 	struct ct_timer *atimer = ti->timer_base;
371 	atimer->ops->start(ti);
372 }
373 
374 void ct_timer_stop(struct ct_timer_instance *ti)
375 {
376 	struct ct_timer *atimer = ti->timer_base;
377 	atimer->ops->stop(ti);
378 }
379 
380 void ct_timer_instance_free(struct ct_timer_instance *ti)
381 {
382 	struct ct_timer *atimer = ti->timer_base;
383 
384 	atimer->ops->stop(ti); /* to be sure */
385 	if (atimer->ops->free_instance)
386 		atimer->ops->free_instance(ti);
387 
388 	spin_lock_irq(&atimer->list_lock);
389 	list_del(&ti->instance_list);
390 	spin_unlock_irq(&atimer->list_lock);
391 
392 	kfree(ti);
393 }
394 
395 /*
396  * timer manager
397  */
398 
399 static void ct_timer_interrupt(void *data, unsigned int status)
400 {
401 	struct ct_timer *timer = data;
402 
403 	/* Interval timer interrupt */
404 	if ((status & IT_INT) && timer->ops->interrupt)
405 		timer->ops->interrupt(timer);
406 }
407 
408 struct ct_timer *ct_timer_new(struct ct_atc *atc)
409 {
410 	struct ct_timer *atimer;
411 	struct hw *hw;
412 
413 	atimer = kzalloc(sizeof(*atimer), GFP_KERNEL);
414 	if (!atimer)
415 		return NULL;
416 	spin_lock_init(&atimer->lock);
417 	spin_lock_init(&atimer->list_lock);
418 	INIT_LIST_HEAD(&atimer->instance_head);
419 	INIT_LIST_HEAD(&atimer->running_head);
420 	atimer->atc = atc;
421 	hw = atc->hw;
422 	if (!use_system_timer && hw->set_timer_irq) {
423 		dev_info(atc->card->dev, "Use xfi-native timer\n");
424 		atimer->ops = &ct_xfitimer_ops;
425 		hw->irq_callback_data = atimer;
426 		hw->irq_callback = ct_timer_interrupt;
427 	} else {
428 		dev_info(atc->card->dev, "Use system timer\n");
429 		atimer->ops = &ct_systimer_ops;
430 	}
431 	return atimer;
432 }
433 
434 void ct_timer_free(struct ct_timer *atimer)
435 {
436 	struct hw *hw = atimer->atc->hw;
437 	hw->irq_callback = NULL;
438 	if (atimer->ops->free_global)
439 		atimer->ops->free_global(atimer);
440 	kfree(atimer);
441 }
442 
443