linux/sound/pci/ctxfi/cttimer.c
<<
>>
Prefs
   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
  18static bool use_system_timer;
  19MODULE_PARM_DESC(use_system_timer, "Force to use system-timer");
  20module_param(use_system_timer, bool, S_IRUGO);
  21
  22struct 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 */
  33struct 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 */
  48struct 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
  66static 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
  94static void ct_systimer_init(struct ct_timer_instance *ti)
  95{
  96        timer_setup(&ti->timer, ct_systimer_callback, 0);
  97}
  98
  99static 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
 112static 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
 122static 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
 130static 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
 147static 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
 158static 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
 168static 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 */
 182static 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 */
 232static 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 */
 248static 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
 266static 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 */
 275static 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
 292static 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
 307static 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
 319static void ct_xfitimer_free_global(struct ct_timer *atimer)
 320{
 321        ct_xfitimer_irq_stop(atimer);
 322}
 323
 324static 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
 336struct ct_timer_instance *
 337ct_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
 360void 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
 368void ct_timer_start(struct ct_timer_instance *ti)
 369{
 370        struct ct_timer *atimer = ti->timer_base;
 371        atimer->ops->start(ti);
 372}
 373
 374void ct_timer_stop(struct ct_timer_instance *ti)
 375{
 376        struct ct_timer *atimer = ti->timer_base;
 377        atimer->ops->stop(ti);
 378}
 379
 380void 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
 399static 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
 408struct 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
 434void 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