cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

seq_timer.c (11972B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *   ALSA sequencer Timer
      4 *   Copyright (c) 1998-1999 by Frank van de Pol <fvdpol@coil.demon.nl>
      5 *                              Jaroslav Kysela <perex@perex.cz>
      6 */
      7
      8#include <sound/core.h>
      9#include <linux/slab.h>
     10#include "seq_timer.h"
     11#include "seq_queue.h"
     12#include "seq_info.h"
     13
     14/* allowed sequencer timer frequencies, in Hz */
     15#define MIN_FREQUENCY		10
     16#define MAX_FREQUENCY		6250
     17#define DEFAULT_FREQUENCY	1000
     18
     19#define SKEW_BASE	0x10000	/* 16bit shift */
     20
     21static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr)
     22{
     23	if (tmr->tempo < 1000000)
     24		tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq;
     25	else {
     26		/* might overflow.. */
     27		unsigned int s;
     28		s = tmr->tempo % tmr->ppq;
     29		s = (s * 1000) / tmr->ppq;
     30		tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000;
     31		tmr->tick.resolution += s;
     32	}
     33	if (tmr->tick.resolution <= 0)
     34		tmr->tick.resolution = 1;
     35	snd_seq_timer_update_tick(&tmr->tick, 0);
     36}
     37
     38/* create new timer (constructor) */
     39struct snd_seq_timer *snd_seq_timer_new(void)
     40{
     41	struct snd_seq_timer *tmr;
     42	
     43	tmr = kzalloc(sizeof(*tmr), GFP_KERNEL);
     44	if (!tmr)
     45		return NULL;
     46	spin_lock_init(&tmr->lock);
     47
     48	/* reset setup to defaults */
     49	snd_seq_timer_defaults(tmr);
     50	
     51	/* reset time */
     52	snd_seq_timer_reset(tmr);
     53	
     54	return tmr;
     55}
     56
     57/* delete timer (destructor) */
     58void snd_seq_timer_delete(struct snd_seq_timer **tmr)
     59{
     60	struct snd_seq_timer *t = *tmr;
     61	*tmr = NULL;
     62
     63	if (t == NULL) {
     64		pr_debug("ALSA: seq: snd_seq_timer_delete() called with NULL timer\n");
     65		return;
     66	}
     67	t->running = 0;
     68
     69	/* reset time */
     70	snd_seq_timer_stop(t);
     71	snd_seq_timer_reset(t);
     72
     73	kfree(t);
     74}
     75
     76void snd_seq_timer_defaults(struct snd_seq_timer * tmr)
     77{
     78	unsigned long flags;
     79
     80	spin_lock_irqsave(&tmr->lock, flags);
     81	/* setup defaults */
     82	tmr->ppq = 96;		/* 96 PPQ */
     83	tmr->tempo = 500000;	/* 120 BPM */
     84	snd_seq_timer_set_tick_resolution(tmr);
     85	tmr->running = 0;
     86
     87	tmr->type = SNDRV_SEQ_TIMER_ALSA;
     88	tmr->alsa_id.dev_class = seq_default_timer_class;
     89	tmr->alsa_id.dev_sclass = seq_default_timer_sclass;
     90	tmr->alsa_id.card = seq_default_timer_card;
     91	tmr->alsa_id.device = seq_default_timer_device;
     92	tmr->alsa_id.subdevice = seq_default_timer_subdevice;
     93	tmr->preferred_resolution = seq_default_timer_resolution;
     94
     95	tmr->skew = tmr->skew_base = SKEW_BASE;
     96	spin_unlock_irqrestore(&tmr->lock, flags);
     97}
     98
     99static void seq_timer_reset(struct snd_seq_timer *tmr)
    100{
    101	/* reset time & songposition */
    102	tmr->cur_time.tv_sec = 0;
    103	tmr->cur_time.tv_nsec = 0;
    104
    105	tmr->tick.cur_tick = 0;
    106	tmr->tick.fraction = 0;
    107}
    108
    109void snd_seq_timer_reset(struct snd_seq_timer *tmr)
    110{
    111	unsigned long flags;
    112
    113	spin_lock_irqsave(&tmr->lock, flags);
    114	seq_timer_reset(tmr);
    115	spin_unlock_irqrestore(&tmr->lock, flags);
    116}
    117
    118
    119/* called by timer interrupt routine. the period time since previous invocation is passed */
    120static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri,
    121				    unsigned long resolution,
    122				    unsigned long ticks)
    123{
    124	unsigned long flags;
    125	struct snd_seq_queue *q = timeri->callback_data;
    126	struct snd_seq_timer *tmr;
    127
    128	if (q == NULL)
    129		return;
    130	tmr = q->timer;
    131	if (tmr == NULL)
    132		return;
    133	spin_lock_irqsave(&tmr->lock, flags);
    134	if (!tmr->running) {
    135		spin_unlock_irqrestore(&tmr->lock, flags);
    136		return;
    137	}
    138
    139	resolution *= ticks;
    140	if (tmr->skew != tmr->skew_base) {
    141		/* FIXME: assuming skew_base = 0x10000 */
    142		resolution = (resolution >> 16) * tmr->skew +
    143			(((resolution & 0xffff) * tmr->skew) >> 16);
    144	}
    145
    146	/* update timer */
    147	snd_seq_inc_time_nsec(&tmr->cur_time, resolution);
    148
    149	/* calculate current tick */
    150	snd_seq_timer_update_tick(&tmr->tick, resolution);
    151
    152	/* register actual time of this timer update */
    153	ktime_get_ts64(&tmr->last_update);
    154
    155	spin_unlock_irqrestore(&tmr->lock, flags);
    156
    157	/* check queues and dispatch events */
    158	snd_seq_check_queue(q, 1, 0);
    159}
    160
    161/* set current tempo */
    162int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo)
    163{
    164	unsigned long flags;
    165
    166	if (snd_BUG_ON(!tmr))
    167		return -EINVAL;
    168	if (tempo <= 0)
    169		return -EINVAL;
    170	spin_lock_irqsave(&tmr->lock, flags);
    171	if ((unsigned int)tempo != tmr->tempo) {
    172		tmr->tempo = tempo;
    173		snd_seq_timer_set_tick_resolution(tmr);
    174	}
    175	spin_unlock_irqrestore(&tmr->lock, flags);
    176	return 0;
    177}
    178
    179/* set current tempo and ppq in a shot */
    180int snd_seq_timer_set_tempo_ppq(struct snd_seq_timer *tmr, int tempo, int ppq)
    181{
    182	int changed;
    183	unsigned long flags;
    184
    185	if (snd_BUG_ON(!tmr))
    186		return -EINVAL;
    187	if (tempo <= 0 || ppq <= 0)
    188		return -EINVAL;
    189	spin_lock_irqsave(&tmr->lock, flags);
    190	if (tmr->running && (ppq != tmr->ppq)) {
    191		/* refuse to change ppq on running timers */
    192		/* because it will upset the song position (ticks) */
    193		spin_unlock_irqrestore(&tmr->lock, flags);
    194		pr_debug("ALSA: seq: cannot change ppq of a running timer\n");
    195		return -EBUSY;
    196	}
    197	changed = (tempo != tmr->tempo) || (ppq != tmr->ppq);
    198	tmr->tempo = tempo;
    199	tmr->ppq = ppq;
    200	if (changed)
    201		snd_seq_timer_set_tick_resolution(tmr);
    202	spin_unlock_irqrestore(&tmr->lock, flags);
    203	return 0;
    204}
    205
    206/* set current tick position */
    207int snd_seq_timer_set_position_tick(struct snd_seq_timer *tmr,
    208				    snd_seq_tick_time_t position)
    209{
    210	unsigned long flags;
    211
    212	if (snd_BUG_ON(!tmr))
    213		return -EINVAL;
    214
    215	spin_lock_irqsave(&tmr->lock, flags);
    216	tmr->tick.cur_tick = position;
    217	tmr->tick.fraction = 0;
    218	spin_unlock_irqrestore(&tmr->lock, flags);
    219	return 0;
    220}
    221
    222/* set current real-time position */
    223int snd_seq_timer_set_position_time(struct snd_seq_timer *tmr,
    224				    snd_seq_real_time_t position)
    225{
    226	unsigned long flags;
    227
    228	if (snd_BUG_ON(!tmr))
    229		return -EINVAL;
    230
    231	snd_seq_sanity_real_time(&position);
    232	spin_lock_irqsave(&tmr->lock, flags);
    233	tmr->cur_time = position;
    234	spin_unlock_irqrestore(&tmr->lock, flags);
    235	return 0;
    236}
    237
    238/* set timer skew */
    239int snd_seq_timer_set_skew(struct snd_seq_timer *tmr, unsigned int skew,
    240			   unsigned int base)
    241{
    242	unsigned long flags;
    243
    244	if (snd_BUG_ON(!tmr))
    245		return -EINVAL;
    246
    247	/* FIXME */
    248	if (base != SKEW_BASE) {
    249		pr_debug("ALSA: seq: invalid skew base 0x%x\n", base);
    250		return -EINVAL;
    251	}
    252	spin_lock_irqsave(&tmr->lock, flags);
    253	tmr->skew = skew;
    254	spin_unlock_irqrestore(&tmr->lock, flags);
    255	return 0;
    256}
    257
    258int snd_seq_timer_open(struct snd_seq_queue *q)
    259{
    260	struct snd_timer_instance *t;
    261	struct snd_seq_timer *tmr;
    262	char str[32];
    263	int err;
    264
    265	tmr = q->timer;
    266	if (snd_BUG_ON(!tmr))
    267		return -EINVAL;
    268	if (tmr->timeri)
    269		return -EBUSY;
    270	sprintf(str, "sequencer queue %i", q->queue);
    271	if (tmr->type != SNDRV_SEQ_TIMER_ALSA)	/* standard ALSA timer */
    272		return -EINVAL;
    273	if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
    274		tmr->alsa_id.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
    275	t = snd_timer_instance_new(str);
    276	if (!t)
    277		return -ENOMEM;
    278	t->callback = snd_seq_timer_interrupt;
    279	t->callback_data = q;
    280	t->flags |= SNDRV_TIMER_IFLG_AUTO;
    281	err = snd_timer_open(t, &tmr->alsa_id, q->queue);
    282	if (err < 0 && tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE) {
    283		if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_GLOBAL ||
    284		    tmr->alsa_id.device != SNDRV_TIMER_GLOBAL_SYSTEM) {
    285			struct snd_timer_id tid;
    286			memset(&tid, 0, sizeof(tid));
    287			tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
    288			tid.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
    289			tid.card = -1;
    290			tid.device = SNDRV_TIMER_GLOBAL_SYSTEM;
    291			err = snd_timer_open(t, &tid, q->queue);
    292		}
    293	}
    294	if (err < 0) {
    295		pr_err("ALSA: seq fatal error: cannot create timer (%i)\n", err);
    296		snd_timer_instance_free(t);
    297		return err;
    298	}
    299	spin_lock_irq(&tmr->lock);
    300	if (tmr->timeri)
    301		err = -EBUSY;
    302	else
    303		tmr->timeri = t;
    304	spin_unlock_irq(&tmr->lock);
    305	if (err < 0) {
    306		snd_timer_close(t);
    307		snd_timer_instance_free(t);
    308		return err;
    309	}
    310	return 0;
    311}
    312
    313int snd_seq_timer_close(struct snd_seq_queue *q)
    314{
    315	struct snd_seq_timer *tmr;
    316	struct snd_timer_instance *t;
    317	
    318	tmr = q->timer;
    319	if (snd_BUG_ON(!tmr))
    320		return -EINVAL;
    321	spin_lock_irq(&tmr->lock);
    322	t = tmr->timeri;
    323	tmr->timeri = NULL;
    324	spin_unlock_irq(&tmr->lock);
    325	if (t) {
    326		snd_timer_close(t);
    327		snd_timer_instance_free(t);
    328	}
    329	return 0;
    330}
    331
    332static int seq_timer_stop(struct snd_seq_timer *tmr)
    333{
    334	if (! tmr->timeri)
    335		return -EINVAL;
    336	if (!tmr->running)
    337		return 0;
    338	tmr->running = 0;
    339	snd_timer_pause(tmr->timeri);
    340	return 0;
    341}
    342
    343int snd_seq_timer_stop(struct snd_seq_timer *tmr)
    344{
    345	unsigned long flags;
    346	int err;
    347
    348	spin_lock_irqsave(&tmr->lock, flags);
    349	err = seq_timer_stop(tmr);
    350	spin_unlock_irqrestore(&tmr->lock, flags);
    351	return err;
    352}
    353
    354static int initialize_timer(struct snd_seq_timer *tmr)
    355{
    356	struct snd_timer *t;
    357	unsigned long freq;
    358
    359	t = tmr->timeri->timer;
    360	if (!t)
    361		return -EINVAL;
    362
    363	freq = tmr->preferred_resolution;
    364	if (!freq)
    365		freq = DEFAULT_FREQUENCY;
    366	else if (freq < MIN_FREQUENCY)
    367		freq = MIN_FREQUENCY;
    368	else if (freq > MAX_FREQUENCY)
    369		freq = MAX_FREQUENCY;
    370
    371	tmr->ticks = 1;
    372	if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) {
    373		unsigned long r = snd_timer_resolution(tmr->timeri);
    374		if (r) {
    375			tmr->ticks = (unsigned int)(1000000000uL / (r * freq));
    376			if (! tmr->ticks)
    377				tmr->ticks = 1;
    378		}
    379	}
    380	tmr->initialized = 1;
    381	return 0;
    382}
    383
    384static int seq_timer_start(struct snd_seq_timer *tmr)
    385{
    386	if (! tmr->timeri)
    387		return -EINVAL;
    388	if (tmr->running)
    389		seq_timer_stop(tmr);
    390	seq_timer_reset(tmr);
    391	if (initialize_timer(tmr) < 0)
    392		return -EINVAL;
    393	snd_timer_start(tmr->timeri, tmr->ticks);
    394	tmr->running = 1;
    395	ktime_get_ts64(&tmr->last_update);
    396	return 0;
    397}
    398
    399int snd_seq_timer_start(struct snd_seq_timer *tmr)
    400{
    401	unsigned long flags;
    402	int err;
    403
    404	spin_lock_irqsave(&tmr->lock, flags);
    405	err = seq_timer_start(tmr);
    406	spin_unlock_irqrestore(&tmr->lock, flags);
    407	return err;
    408}
    409
    410static int seq_timer_continue(struct snd_seq_timer *tmr)
    411{
    412	if (! tmr->timeri)
    413		return -EINVAL;
    414	if (tmr->running)
    415		return -EBUSY;
    416	if (! tmr->initialized) {
    417		seq_timer_reset(tmr);
    418		if (initialize_timer(tmr) < 0)
    419			return -EINVAL;
    420	}
    421	snd_timer_start(tmr->timeri, tmr->ticks);
    422	tmr->running = 1;
    423	ktime_get_ts64(&tmr->last_update);
    424	return 0;
    425}
    426
    427int snd_seq_timer_continue(struct snd_seq_timer *tmr)
    428{
    429	unsigned long flags;
    430	int err;
    431
    432	spin_lock_irqsave(&tmr->lock, flags);
    433	err = seq_timer_continue(tmr);
    434	spin_unlock_irqrestore(&tmr->lock, flags);
    435	return err;
    436}
    437
    438/* return current 'real' time. use timeofday() to get better granularity. */
    439snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr,
    440					       bool adjust_ktime)
    441{
    442	snd_seq_real_time_t cur_time;
    443	unsigned long flags;
    444
    445	spin_lock_irqsave(&tmr->lock, flags);
    446	cur_time = tmr->cur_time;
    447	if (adjust_ktime && tmr->running) {
    448		struct timespec64 tm;
    449
    450		ktime_get_ts64(&tm);
    451		tm = timespec64_sub(tm, tmr->last_update);
    452		cur_time.tv_nsec += tm.tv_nsec;
    453		cur_time.tv_sec += tm.tv_sec;
    454		snd_seq_sanity_real_time(&cur_time);
    455	}
    456	spin_unlock_irqrestore(&tmr->lock, flags);
    457	return cur_time;	
    458}
    459
    460/* TODO: use interpolation on tick queue (will only be useful for very
    461 high PPQ values) */
    462snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr)
    463{
    464	snd_seq_tick_time_t cur_tick;
    465	unsigned long flags;
    466
    467	spin_lock_irqsave(&tmr->lock, flags);
    468	cur_tick = tmr->tick.cur_tick;
    469	spin_unlock_irqrestore(&tmr->lock, flags);
    470	return cur_tick;
    471}
    472
    473
    474#ifdef CONFIG_SND_PROC_FS
    475/* exported to seq_info.c */
    476void snd_seq_info_timer_read(struct snd_info_entry *entry,
    477			     struct snd_info_buffer *buffer)
    478{
    479	int idx;
    480	struct snd_seq_queue *q;
    481	struct snd_seq_timer *tmr;
    482	struct snd_timer_instance *ti;
    483	unsigned long resolution;
    484	
    485	for (idx = 0; idx < SNDRV_SEQ_MAX_QUEUES; idx++) {
    486		q = queueptr(idx);
    487		if (q == NULL)
    488			continue;
    489		mutex_lock(&q->timer_mutex);
    490		tmr = q->timer;
    491		if (!tmr)
    492			goto unlock;
    493		ti = tmr->timeri;
    494		if (!ti)
    495			goto unlock;
    496		snd_iprintf(buffer, "Timer for queue %i : %s\n", q->queue, ti->timer->name);
    497		resolution = snd_timer_resolution(ti) * tmr->ticks;
    498		snd_iprintf(buffer, "  Period time : %lu.%09lu\n", resolution / 1000000000, resolution % 1000000000);
    499		snd_iprintf(buffer, "  Skew : %u / %u\n", tmr->skew, tmr->skew_base);
    500unlock:
    501		mutex_unlock(&q->timer_mutex);
    502		queuefree(q);
    503 	}
    504}
    505#endif /* CONFIG_SND_PROC_FS */
    506