2
* PCM timer handling on ctxfi
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.
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>
15
#include "cthardware.h"
18
static int use_system_timer;
19
MODULE_PARM_DESC(use_system_timer, "Foce to use system-timer");
20
module_param(use_system_timer, bool, S_IRUGO);
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 *);
32
/* timer instance -- assigned to each PCM stream */
33
struct ct_timer_instance {
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;
47
/* timer instance manager */
49
spinlock_t lock; /* global timer lock (for xfitimer) */
50
spinlock_t list_lock; /* lock for instance list */
52
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 */
63
* system-timer-based updates
66
static void ct_systimer_callback(unsigned long data)
68
struct ct_timer_instance *ti = (struct ct_timer_instance *)data;
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;
75
unsigned int position, dist, interval;
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;
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);
90
mod_timer(&ti->timer, jiffies + interval);
91
spin_unlock_irqrestore(&ti->lock, flags);
94
static void ct_systimer_init(struct ct_timer_instance *ti)
96
setup_timer(&ti->timer, ct_systimer_callback,
100
static void ct_systimer_start(struct ct_timer_instance *ti)
102
struct snd_pcm_runtime *runtime = ti->substream->runtime;
105
spin_lock_irqsave(&ti->lock, flags);
107
mod_timer(&ti->timer,
108
jiffies + (runtime->period_size * HZ +
109
(runtime->rate - 1)) / runtime->rate);
110
spin_unlock_irqrestore(&ti->lock, flags);
113
static void ct_systimer_stop(struct ct_timer_instance *ti)
117
spin_lock_irqsave(&ti->lock, flags);
119
del_timer(&ti->timer);
120
spin_unlock_irqrestore(&ti->lock, flags);
123
static void ct_systimer_prepare(struct ct_timer_instance *ti)
125
ct_systimer_stop(ti);
126
try_to_del_timer_sync(&ti->timer);
129
#define ct_systimer_free ct_systimer_prepare
131
static struct ct_timer_ops ct_systimer_ops = {
132
.init = ct_systimer_init,
133
.free_instance = ct_systimer_free,
134
.prepare = ct_systimer_prepare,
135
.start = ct_systimer_start,
136
.stop = ct_systimer_stop,
141
* Handling multiple streams using a global emu20k1 timer irq
144
#define CT_TIMER_FREQ 48000
146
#define MAX_TICKS ((1 << 13) - 1)
148
static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks)
150
struct hw *hw = atimer->atc->hw;
151
if (ticks > MAX_TICKS)
153
hw->set_timer_tick(hw, ticks);
154
if (!atimer->running)
155
hw->set_timer_irq(hw, 1);
159
static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
161
if (atimer->running) {
162
struct hw *hw = atimer->atc->hw;
163
hw->set_timer_irq(hw, 0);
164
hw->set_timer_tick(hw, 0);
169
static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
171
struct hw *hw = atimer->atc->hw;
172
return hw->get_wc(hw);
176
* reprogram the timer interval;
177
* checks the running instance list and determines the next timer interval.
178
* also updates the each stream position, returns the number of streams
179
* to call snd_pcm_period_elapsed() appropriately
181
* call this inside the lock and irq disabled
183
static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update)
185
struct ct_timer_instance *ti;
186
unsigned int min_intr = (unsigned int)-1;
188
unsigned int wc, diff;
190
if (list_empty(&atimer->running_head)) {
191
ct_xfitimer_irq_stop(atimer);
192
atimer->reprogram = 0; /* clear flag */
196
wc = ct_xfitimer_get_wc(atimer);
197
diff = wc - atimer->wc;
199
list_for_each_entry(ti, &atimer->running_head, running_list) {
200
if (ti->frag_count > diff)
201
ti->frag_count -= diff;
204
unsigned int period_size, rate;
206
period_size = ti->substream->runtime->period_size;
207
rate = ti->substream->runtime->rate;
208
pos = ti->substream->ops->pointer(ti->substream);
209
if (pos / period_size != ti->position / period_size) {
215
pos = period_size - pos;
216
ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
219
if (ti->need_update && !can_update)
220
min_intr = 0; /* pending to the next irq */
221
if (ti->frag_count < min_intr)
222
min_intr = ti->frag_count;
225
if (min_intr < MIN_TICKS)
226
min_intr = MIN_TICKS;
227
ct_xfitimer_irq_rearm(atimer, min_intr);
228
atimer->reprogram = 0; /* clear flag */
232
/* look through the instance list and call period_elapsed if needed */
233
static void ct_xfitimer_check_period(struct ct_timer *atimer)
235
struct ct_timer_instance *ti;
238
spin_lock_irqsave(&atimer->list_lock, flags);
239
list_for_each_entry(ti, &atimer->instance_head, instance_list) {
240
if (ti->running && ti->need_update) {
242
ti->apcm->interrupt(ti->apcm);
245
spin_unlock_irqrestore(&atimer->list_lock, flags);
248
/* Handle timer-interrupt */
249
static void ct_xfitimer_callback(struct ct_timer *atimer)
254
spin_lock_irqsave(&atimer->lock, flags);
255
atimer->irq_handling = 1;
257
update = ct_xfitimer_reprogram(atimer, 1);
258
spin_unlock(&atimer->lock);
260
ct_xfitimer_check_period(atimer);
261
spin_lock(&atimer->lock);
262
} while (atimer->reprogram);
263
atimer->irq_handling = 0;
264
spin_unlock_irqrestore(&atimer->lock, flags);
267
static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
269
ti->frag_count = ti->substream->runtime->period_size;
275
/* start/stop the timer */
276
static void ct_xfitimer_update(struct ct_timer *atimer)
280
spin_lock_irqsave(&atimer->lock, flags);
281
if (atimer->irq_handling) {
282
/* reached from IRQ handler; let it handle later */
283
atimer->reprogram = 1;
284
spin_unlock_irqrestore(&atimer->lock, flags);
288
ct_xfitimer_irq_stop(atimer);
289
ct_xfitimer_reprogram(atimer, 0);
290
spin_unlock_irqrestore(&atimer->lock, flags);
293
static void ct_xfitimer_start(struct ct_timer_instance *ti)
295
struct ct_timer *atimer = ti->timer_base;
298
spin_lock_irqsave(&atimer->lock, flags);
299
if (list_empty(&ti->running_list))
300
atimer->wc = ct_xfitimer_get_wc(atimer);
303
list_add(&ti->running_list, &atimer->running_head);
304
spin_unlock_irqrestore(&atimer->lock, flags);
305
ct_xfitimer_update(atimer);
308
static void ct_xfitimer_stop(struct ct_timer_instance *ti)
310
struct ct_timer *atimer = ti->timer_base;
313
spin_lock_irqsave(&atimer->lock, flags);
314
list_del_init(&ti->running_list);
316
spin_unlock_irqrestore(&atimer->lock, flags);
317
ct_xfitimer_update(atimer);
320
static void ct_xfitimer_free_global(struct ct_timer *atimer)
322
ct_xfitimer_irq_stop(atimer);
325
static struct ct_timer_ops ct_xfitimer_ops = {
326
.prepare = ct_xfitimer_prepare,
327
.start = ct_xfitimer_start,
328
.stop = ct_xfitimer_stop,
329
.interrupt = ct_xfitimer_callback,
330
.free_global = ct_xfitimer_free_global,
337
struct ct_timer_instance *
338
ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm)
340
struct ct_timer_instance *ti;
342
ti = kzalloc(sizeof(*ti), GFP_KERNEL);
345
spin_lock_init(&ti->lock);
346
INIT_LIST_HEAD(&ti->instance_list);
347
INIT_LIST_HEAD(&ti->running_list);
348
ti->timer_base = atimer;
350
ti->substream = apcm->substream;
351
if (atimer->ops->init)
352
atimer->ops->init(ti);
354
spin_lock_irq(&atimer->list_lock);
355
list_add(&ti->instance_list, &atimer->instance_head);
356
spin_unlock_irq(&atimer->list_lock);
361
void ct_timer_prepare(struct ct_timer_instance *ti)
363
if (ti->timer_base->ops->prepare)
364
ti->timer_base->ops->prepare(ti);
369
void ct_timer_start(struct ct_timer_instance *ti)
371
struct ct_timer *atimer = ti->timer_base;
372
atimer->ops->start(ti);
375
void ct_timer_stop(struct ct_timer_instance *ti)
377
struct ct_timer *atimer = ti->timer_base;
378
atimer->ops->stop(ti);
381
void ct_timer_instance_free(struct ct_timer_instance *ti)
383
struct ct_timer *atimer = ti->timer_base;
385
atimer->ops->stop(ti); /* to be sure */
386
if (atimer->ops->free_instance)
387
atimer->ops->free_instance(ti);
389
spin_lock_irq(&atimer->list_lock);
390
list_del(&ti->instance_list);
391
spin_unlock_irq(&atimer->list_lock);
400
static void ct_timer_interrupt(void *data, unsigned int status)
402
struct ct_timer *timer = data;
404
/* Interval timer interrupt */
405
if ((status & IT_INT) && timer->ops->interrupt)
406
timer->ops->interrupt(timer);
409
struct ct_timer *ct_timer_new(struct ct_atc *atc)
411
struct ct_timer *atimer;
414
atimer = kzalloc(sizeof(*atimer), GFP_KERNEL);
417
spin_lock_init(&atimer->lock);
418
spin_lock_init(&atimer->list_lock);
419
INIT_LIST_HEAD(&atimer->instance_head);
420
INIT_LIST_HEAD(&atimer->running_head);
423
if (!use_system_timer && hw->set_timer_irq) {
424
snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n");
425
atimer->ops = &ct_xfitimer_ops;
426
hw->irq_callback_data = atimer;
427
hw->irq_callback = ct_timer_interrupt;
429
snd_printd(KERN_INFO "ctxfi: Use system timer\n");
430
atimer->ops = &ct_systimer_ops;
435
void ct_timer_free(struct ct_timer *atimer)
437
struct hw *hw = atimer->atc->hw;
438
hw->irq_callback = NULL;
439
if (atimer->ops->free_global)
440
atimer->ops->free_global(atimer);