Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * PCM timer handling on ctxfi
0004  */
0005 
0006 #include <linux/slab.h>
0007 #include <linux/math64.h>
0008 #include <linux/moduleparam.h>
0009 #include <sound/core.h>
0010 #include <sound/pcm.h>
0011 #include "ctatc.h"
0012 #include "cthardware.h"
0013 #include "cttimer.h"
0014 
0015 static bool use_system_timer;
0016 MODULE_PARM_DESC(use_system_timer, "Force to use system-timer");
0017 module_param(use_system_timer, bool, 0444);
0018 
0019 struct ct_timer_ops {
0020     void (*init)(struct ct_timer_instance *);
0021     void (*prepare)(struct ct_timer_instance *);
0022     void (*start)(struct ct_timer_instance *);
0023     void (*stop)(struct ct_timer_instance *);
0024     void (*free_instance)(struct ct_timer_instance *);
0025     void (*interrupt)(struct ct_timer *);
0026     void (*free_global)(struct ct_timer *);
0027 };
0028 
0029 /* timer instance -- assigned to each PCM stream */
0030 struct ct_timer_instance {
0031     spinlock_t lock;
0032     struct ct_timer *timer_base;
0033     struct ct_atc_pcm *apcm;
0034     struct snd_pcm_substream *substream;
0035     struct timer_list timer;
0036     struct list_head instance_list;
0037     struct list_head running_list;
0038     unsigned int position;
0039     unsigned int frag_count;
0040     unsigned int running:1;
0041     unsigned int need_update:1;
0042 };
0043 
0044 /* timer instance manager */
0045 struct ct_timer {
0046     spinlock_t lock;        /* global timer lock (for xfitimer) */
0047     spinlock_t list_lock;       /* lock for instance list */
0048     struct ct_atc *atc;
0049     const struct ct_timer_ops *ops;
0050     struct list_head instance_head;
0051     struct list_head running_head;
0052     unsigned int wc;        /* current wallclock */
0053     unsigned int irq_handling:1;    /* in IRQ handling */
0054     unsigned int reprogram:1;   /* need to reprogram the internval */
0055     unsigned int running:1;     /* global timer running */
0056 };
0057 
0058 
0059 /*
0060  * system-timer-based updates
0061  */
0062 
0063 static void ct_systimer_callback(struct timer_list *t)
0064 {
0065     struct ct_timer_instance *ti = from_timer(ti, t, timer);
0066     struct snd_pcm_substream *substream = ti->substream;
0067     struct snd_pcm_runtime *runtime = substream->runtime;
0068     struct ct_atc_pcm *apcm = ti->apcm;
0069     unsigned int period_size = runtime->period_size;
0070     unsigned int buffer_size = runtime->buffer_size;
0071     unsigned long flags;
0072     unsigned int position, dist, interval;
0073 
0074     position = substream->ops->pointer(substream);
0075     dist = (position + buffer_size - ti->position) % buffer_size;
0076     if (dist >= period_size ||
0077         position / period_size != ti->position / period_size) {
0078         apcm->interrupt(apcm);
0079         ti->position = position;
0080     }
0081     /* Add extra HZ*5/1000 to avoid overrun issue when recording
0082      * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
0083     interval = ((period_size - (position % period_size))
0084            * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000;
0085     spin_lock_irqsave(&ti->lock, flags);
0086     if (ti->running)
0087         mod_timer(&ti->timer, jiffies + interval);
0088     spin_unlock_irqrestore(&ti->lock, flags);
0089 }
0090 
0091 static void ct_systimer_init(struct ct_timer_instance *ti)
0092 {
0093     timer_setup(&ti->timer, ct_systimer_callback, 0);
0094 }
0095 
0096 static void ct_systimer_start(struct ct_timer_instance *ti)
0097 {
0098     struct snd_pcm_runtime *runtime = ti->substream->runtime;
0099     unsigned long flags;
0100 
0101     spin_lock_irqsave(&ti->lock, flags);
0102     ti->running = 1;
0103     mod_timer(&ti->timer,
0104           jiffies + (runtime->period_size * HZ +
0105                  (runtime->rate - 1)) / runtime->rate);
0106     spin_unlock_irqrestore(&ti->lock, flags);
0107 }
0108 
0109 static void ct_systimer_stop(struct ct_timer_instance *ti)
0110 {
0111     unsigned long flags;
0112 
0113     spin_lock_irqsave(&ti->lock, flags);
0114     ti->running = 0;
0115     del_timer(&ti->timer);
0116     spin_unlock_irqrestore(&ti->lock, flags);
0117 }
0118 
0119 static void ct_systimer_prepare(struct ct_timer_instance *ti)
0120 {
0121     ct_systimer_stop(ti);
0122     try_to_del_timer_sync(&ti->timer);
0123 }
0124 
0125 #define ct_systimer_free    ct_systimer_prepare
0126 
0127 static const struct ct_timer_ops ct_systimer_ops = {
0128     .init = ct_systimer_init,
0129     .free_instance = ct_systimer_free,
0130     .prepare = ct_systimer_prepare,
0131     .start = ct_systimer_start,
0132     .stop = ct_systimer_stop,
0133 };
0134 
0135 
0136 /*
0137  * Handling multiple streams using a global emu20k1 timer irq
0138  */
0139 
0140 #define CT_TIMER_FREQ   48000
0141 #define MIN_TICKS   1
0142 #define MAX_TICKS   ((1 << 13) - 1)
0143 
0144 static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks)
0145 {
0146     struct hw *hw = atimer->atc->hw;
0147     if (ticks > MAX_TICKS)
0148         ticks = MAX_TICKS;
0149     hw->set_timer_tick(hw, ticks);
0150     if (!atimer->running)
0151         hw->set_timer_irq(hw, 1);
0152     atimer->running = 1;
0153 }
0154 
0155 static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
0156 {
0157     if (atimer->running) {
0158         struct hw *hw = atimer->atc->hw;
0159         hw->set_timer_irq(hw, 0);
0160         hw->set_timer_tick(hw, 0);
0161         atimer->running = 0;
0162     }
0163 }
0164 
0165 static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
0166 {
0167     struct hw *hw = atimer->atc->hw;
0168     return hw->get_wc(hw);
0169 }
0170 
0171 /*
0172  * reprogram the timer interval;
0173  * checks the running instance list and determines the next timer interval.
0174  * also updates the each stream position, returns the number of streams
0175  * to call snd_pcm_period_elapsed() appropriately
0176  *
0177  * call this inside the lock and irq disabled
0178  */
0179 static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update)
0180 {
0181     struct ct_timer_instance *ti;
0182     unsigned int min_intr = (unsigned int)-1;
0183     int updates = 0;
0184     unsigned int wc, diff;
0185 
0186     if (list_empty(&atimer->running_head)) {
0187         ct_xfitimer_irq_stop(atimer);
0188         atimer->reprogram = 0; /* clear flag */
0189         return 0;
0190     }
0191 
0192     wc = ct_xfitimer_get_wc(atimer);
0193     diff = wc - atimer->wc;
0194     atimer->wc = wc;
0195     list_for_each_entry(ti, &atimer->running_head, running_list) {
0196         if (ti->frag_count > diff)
0197             ti->frag_count -= diff;
0198         else {
0199             unsigned int pos;
0200             unsigned int period_size, rate;
0201 
0202             period_size = ti->substream->runtime->period_size;
0203             rate = ti->substream->runtime->rate;
0204             pos = ti->substream->ops->pointer(ti->substream);
0205             if (pos / period_size != ti->position / period_size) {
0206                 ti->need_update = 1;
0207                 ti->position = pos;
0208                 updates++;
0209             }
0210             pos %= period_size;
0211             pos = period_size - pos;
0212             ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
0213                          rate - 1, rate);
0214         }
0215         if (ti->need_update && !can_update)
0216             min_intr = 0; /* pending to the next irq */
0217         if (ti->frag_count < min_intr)
0218             min_intr = ti->frag_count;
0219     }
0220 
0221     if (min_intr < MIN_TICKS)
0222         min_intr = MIN_TICKS;
0223     ct_xfitimer_irq_rearm(atimer, min_intr);
0224     atimer->reprogram = 0; /* clear flag */
0225     return updates;
0226 }
0227 
0228 /* look through the instance list and call period_elapsed if needed */
0229 static void ct_xfitimer_check_period(struct ct_timer *atimer)
0230 {
0231     struct ct_timer_instance *ti;
0232     unsigned long flags;
0233 
0234     spin_lock_irqsave(&atimer->list_lock, flags);
0235     list_for_each_entry(ti, &atimer->instance_head, instance_list) {
0236         if (ti->running && ti->need_update) {
0237             ti->need_update = 0;
0238             ti->apcm->interrupt(ti->apcm);
0239         }
0240     }
0241     spin_unlock_irqrestore(&atimer->list_lock, flags);
0242 }
0243 
0244 /* Handle timer-interrupt */
0245 static void ct_xfitimer_callback(struct ct_timer *atimer)
0246 {
0247     int update;
0248     unsigned long flags;
0249 
0250     spin_lock_irqsave(&atimer->lock, flags);
0251     atimer->irq_handling = 1;
0252     do {
0253         update = ct_xfitimer_reprogram(atimer, 1);
0254         spin_unlock(&atimer->lock);
0255         if (update)
0256             ct_xfitimer_check_period(atimer);
0257         spin_lock(&atimer->lock);
0258     } while (atimer->reprogram);
0259     atimer->irq_handling = 0;
0260     spin_unlock_irqrestore(&atimer->lock, flags);
0261 }
0262 
0263 static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
0264 {
0265     ti->frag_count = ti->substream->runtime->period_size;
0266     ti->running = 0;
0267     ti->need_update = 0;
0268 }
0269 
0270 
0271 /* start/stop the timer */
0272 static void ct_xfitimer_update(struct ct_timer *atimer)
0273 {
0274     unsigned long flags;
0275 
0276     spin_lock_irqsave(&atimer->lock, flags);
0277     if (atimer->irq_handling) {
0278         /* reached from IRQ handler; let it handle later */
0279         atimer->reprogram = 1;
0280         spin_unlock_irqrestore(&atimer->lock, flags);
0281         return;
0282     }
0283 
0284     ct_xfitimer_irq_stop(atimer);
0285     ct_xfitimer_reprogram(atimer, 0);
0286     spin_unlock_irqrestore(&atimer->lock, flags);
0287 }
0288 
0289 static void ct_xfitimer_start(struct ct_timer_instance *ti)
0290 {
0291     struct ct_timer *atimer = ti->timer_base;
0292     unsigned long flags;
0293 
0294     spin_lock_irqsave(&atimer->lock, flags);
0295     if (list_empty(&ti->running_list))
0296         atimer->wc = ct_xfitimer_get_wc(atimer);
0297     ti->running = 1;
0298     ti->need_update = 0;
0299     list_add(&ti->running_list, &atimer->running_head);
0300     spin_unlock_irqrestore(&atimer->lock, flags);
0301     ct_xfitimer_update(atimer);
0302 }
0303 
0304 static void ct_xfitimer_stop(struct ct_timer_instance *ti)
0305 {
0306     struct ct_timer *atimer = ti->timer_base;
0307     unsigned long flags;
0308 
0309     spin_lock_irqsave(&atimer->lock, flags);
0310     list_del_init(&ti->running_list);
0311     ti->running = 0;
0312     spin_unlock_irqrestore(&atimer->lock, flags);
0313     ct_xfitimer_update(atimer);
0314 }
0315 
0316 static void ct_xfitimer_free_global(struct ct_timer *atimer)
0317 {
0318     ct_xfitimer_irq_stop(atimer);
0319 }
0320 
0321 static const struct ct_timer_ops ct_xfitimer_ops = {
0322     .prepare = ct_xfitimer_prepare,
0323     .start = ct_xfitimer_start,
0324     .stop = ct_xfitimer_stop,
0325     .interrupt = ct_xfitimer_callback,
0326     .free_global = ct_xfitimer_free_global,
0327 };
0328 
0329 /*
0330  * timer instance
0331  */
0332 
0333 struct ct_timer_instance *
0334 ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm)
0335 {
0336     struct ct_timer_instance *ti;
0337 
0338     ti = kzalloc(sizeof(*ti), GFP_KERNEL);
0339     if (!ti)
0340         return NULL;
0341     spin_lock_init(&ti->lock);
0342     INIT_LIST_HEAD(&ti->instance_list);
0343     INIT_LIST_HEAD(&ti->running_list);
0344     ti->timer_base = atimer;
0345     ti->apcm = apcm;
0346     ti->substream = apcm->substream;
0347     if (atimer->ops->init)
0348         atimer->ops->init(ti);
0349 
0350     spin_lock_irq(&atimer->list_lock);
0351     list_add(&ti->instance_list, &atimer->instance_head);
0352     spin_unlock_irq(&atimer->list_lock);
0353 
0354     return ti;
0355 }
0356 
0357 void ct_timer_prepare(struct ct_timer_instance *ti)
0358 {
0359     if (ti->timer_base->ops->prepare)
0360         ti->timer_base->ops->prepare(ti);
0361     ti->position = 0;
0362     ti->running = 0;
0363 }
0364 
0365 void ct_timer_start(struct ct_timer_instance *ti)
0366 {
0367     struct ct_timer *atimer = ti->timer_base;
0368     atimer->ops->start(ti);
0369 }
0370 
0371 void ct_timer_stop(struct ct_timer_instance *ti)
0372 {
0373     struct ct_timer *atimer = ti->timer_base;
0374     atimer->ops->stop(ti);
0375 }
0376 
0377 void ct_timer_instance_free(struct ct_timer_instance *ti)
0378 {
0379     struct ct_timer *atimer = ti->timer_base;
0380 
0381     atimer->ops->stop(ti); /* to be sure */
0382     if (atimer->ops->free_instance)
0383         atimer->ops->free_instance(ti);
0384 
0385     spin_lock_irq(&atimer->list_lock);
0386     list_del(&ti->instance_list);
0387     spin_unlock_irq(&atimer->list_lock);
0388 
0389     kfree(ti);
0390 }
0391 
0392 /*
0393  * timer manager
0394  */
0395 
0396 static void ct_timer_interrupt(void *data, unsigned int status)
0397 {
0398     struct ct_timer *timer = data;
0399 
0400     /* Interval timer interrupt */
0401     if ((status & IT_INT) && timer->ops->interrupt)
0402         timer->ops->interrupt(timer);
0403 }
0404 
0405 struct ct_timer *ct_timer_new(struct ct_atc *atc)
0406 {
0407     struct ct_timer *atimer;
0408     struct hw *hw;
0409 
0410     atimer = kzalloc(sizeof(*atimer), GFP_KERNEL);
0411     if (!atimer)
0412         return NULL;
0413     spin_lock_init(&atimer->lock);
0414     spin_lock_init(&atimer->list_lock);
0415     INIT_LIST_HEAD(&atimer->instance_head);
0416     INIT_LIST_HEAD(&atimer->running_head);
0417     atimer->atc = atc;
0418     hw = atc->hw;
0419     if (!use_system_timer && hw->set_timer_irq) {
0420         dev_info(atc->card->dev, "Use xfi-native timer\n");
0421         atimer->ops = &ct_xfitimer_ops;
0422         hw->irq_callback_data = atimer;
0423         hw->irq_callback = ct_timer_interrupt;
0424     } else {
0425         dev_info(atc->card->dev, "Use system timer\n");
0426         atimer->ops = &ct_systimer_ops;
0427     }
0428     return atimer;
0429 }
0430 
0431 void ct_timer_free(struct ct_timer *atimer)
0432 {
0433     struct hw *hw = atimer->atc->hw;
0434     hw->irq_callback = NULL;
0435     if (atimer->ops->free_global)
0436         atimer->ops->free_global(atimer);
0437     kfree(atimer);
0438 }
0439