~hui.wang/alsa-driver/tiwai-trunk-fgit

« back to all changes in this revision

Viewing changes to pci/ctxfi/cttimer.c

  • Committer: Hui Wang
  • Date: 2018-06-07 01:04:04 UTC
  • Revision ID: git-v1:baf13208df10376d9e4588ad3524aeb3c9973bdf
sync the alsa hda driver from Takashi's tree

Signed-off-by: Hui Wang <hui.wang@canonical.com>

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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