xref: /openbmc/linux/sound/pci/ctxfi/cttimer.c (revision 2a598d0b)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * PCM timer handling on ctxfi
4  */
5 
6 #include <linux/slab.h>
7 #include <linux/math64.h>
8 #include <linux/moduleparam.h>
9 #include <sound/core.h>
10 #include <sound/pcm.h>
11 #include "ctatc.h"
12 #include "cthardware.h"
13 #include "cttimer.h"
14 
15 static bool use_system_timer;
16 MODULE_PARM_DESC(use_system_timer, "Force to use system-timer");
17 module_param(use_system_timer, bool, 0444);
18 
19 struct ct_timer_ops {
20 	void (*init)(struct ct_timer_instance *);
21 	void (*prepare)(struct ct_timer_instance *);
22 	void (*start)(struct ct_timer_instance *);
23 	void (*stop)(struct ct_timer_instance *);
24 	void (*free_instance)(struct ct_timer_instance *);
25 	void (*interrupt)(struct ct_timer *);
26 	void (*free_global)(struct ct_timer *);
27 };
28 
29 /* timer instance -- assigned to each PCM stream */
30 struct ct_timer_instance {
31 	spinlock_t lock;
32 	struct ct_timer *timer_base;
33 	struct ct_atc_pcm *apcm;
34 	struct snd_pcm_substream *substream;
35 	struct timer_list timer;
36 	struct list_head instance_list;
37 	struct list_head running_list;
38 	unsigned int position;
39 	unsigned int frag_count;
40 	unsigned int running:1;
41 	unsigned int need_update:1;
42 };
43 
44 /* timer instance manager */
45 struct ct_timer {
46 	spinlock_t lock;		/* global timer lock (for xfitimer) */
47 	spinlock_t list_lock;		/* lock for instance list */
48 	struct ct_atc *atc;
49 	const struct ct_timer_ops *ops;
50 	struct list_head instance_head;
51 	struct list_head running_head;
52 	unsigned int wc;		/* current wallclock */
53 	unsigned int irq_handling:1;	/* in IRQ handling */
54 	unsigned int reprogram:1;	/* need to reprogram the internval */
55 	unsigned int running:1;		/* global timer running */
56 };
57 
58 
59 /*
60  * system-timer-based updates
61  */
62 
63 static void ct_systimer_callback(struct timer_list *t)
64 {
65 	struct ct_timer_instance *ti = from_timer(ti, t, timer);
66 	struct snd_pcm_substream *substream = ti->substream;
67 	struct snd_pcm_runtime *runtime = substream->runtime;
68 	struct ct_atc_pcm *apcm = ti->apcm;
69 	unsigned int period_size = runtime->period_size;
70 	unsigned int buffer_size = runtime->buffer_size;
71 	unsigned long flags;
72 	unsigned int position, dist, interval;
73 
74 	position = substream->ops->pointer(substream);
75 	dist = (position + buffer_size - ti->position) % buffer_size;
76 	if (dist >= period_size ||
77 	    position / period_size != ti->position / period_size) {
78 		apcm->interrupt(apcm);
79 		ti->position = position;
80 	}
81 	/* Add extra HZ*5/1000 to avoid overrun issue when recording
82 	 * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
83 	interval = ((period_size - (position % period_size))
84 		   * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000;
85 	spin_lock_irqsave(&ti->lock, flags);
86 	if (ti->running)
87 		mod_timer(&ti->timer, jiffies + interval);
88 	spin_unlock_irqrestore(&ti->lock, flags);
89 }
90 
91 static void ct_systimer_init(struct ct_timer_instance *ti)
92 {
93 	timer_setup(&ti->timer, ct_systimer_callback, 0);
94 }
95 
96 static void ct_systimer_start(struct ct_timer_instance *ti)
97 {
98 	struct snd_pcm_runtime *runtime = ti->substream->runtime;
99 	unsigned long flags;
100 
101 	spin_lock_irqsave(&ti->lock, flags);
102 	ti->running = 1;
103 	mod_timer(&ti->timer,
104 		  jiffies + (runtime->period_size * HZ +
105 			     (runtime->rate - 1)) / runtime->rate);
106 	spin_unlock_irqrestore(&ti->lock, flags);
107 }
108 
109 static void ct_systimer_stop(struct ct_timer_instance *ti)
110 {
111 	unsigned long flags;
112 
113 	spin_lock_irqsave(&ti->lock, flags);
114 	ti->running = 0;
115 	del_timer(&ti->timer);
116 	spin_unlock_irqrestore(&ti->lock, flags);
117 }
118 
119 static void ct_systimer_prepare(struct ct_timer_instance *ti)
120 {
121 	ct_systimer_stop(ti);
122 	try_to_del_timer_sync(&ti->timer);
123 }
124 
125 #define ct_systimer_free	ct_systimer_prepare
126 
127 static const struct ct_timer_ops ct_systimer_ops = {
128 	.init = ct_systimer_init,
129 	.free_instance = ct_systimer_free,
130 	.prepare = ct_systimer_prepare,
131 	.start = ct_systimer_start,
132 	.stop = ct_systimer_stop,
133 };
134 
135 
136 /*
137  * Handling multiple streams using a global emu20k1 timer irq
138  */
139 
140 #define CT_TIMER_FREQ	48000
141 #define MIN_TICKS	1
142 #define MAX_TICKS	((1 << 13) - 1)
143 
144 static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks)
145 {
146 	struct hw *hw = atimer->atc->hw;
147 	if (ticks > MAX_TICKS)
148 		ticks = MAX_TICKS;
149 	hw->set_timer_tick(hw, ticks);
150 	if (!atimer->running)
151 		hw->set_timer_irq(hw, 1);
152 	atimer->running = 1;
153 }
154 
155 static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
156 {
157 	if (atimer->running) {
158 		struct hw *hw = atimer->atc->hw;
159 		hw->set_timer_irq(hw, 0);
160 		hw->set_timer_tick(hw, 0);
161 		atimer->running = 0;
162 	}
163 }
164 
165 static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
166 {
167 	struct hw *hw = atimer->atc->hw;
168 	return hw->get_wc(hw);
169 }
170 
171 /*
172  * reprogram the timer interval;
173  * checks the running instance list and determines the next timer interval.
174  * also updates the each stream position, returns the number of streams
175  * to call snd_pcm_period_elapsed() appropriately
176  *
177  * call this inside the lock and irq disabled
178  */
179 static int ct_xfitimer_reprogram(struct ct_timer *atimer, int can_update)
180 {
181 	struct ct_timer_instance *ti;
182 	unsigned int min_intr = (unsigned int)-1;
183 	int updates = 0;
184 	unsigned int wc, diff;
185 
186 	if (list_empty(&atimer->running_head)) {
187 		ct_xfitimer_irq_stop(atimer);
188 		atimer->reprogram = 0; /* clear flag */
189 		return 0;
190 	}
191 
192 	wc = ct_xfitimer_get_wc(atimer);
193 	diff = wc - atimer->wc;
194 	atimer->wc = wc;
195 	list_for_each_entry(ti, &atimer->running_head, running_list) {
196 		if (ti->frag_count > diff)
197 			ti->frag_count -= diff;
198 		else {
199 			unsigned int pos;
200 			unsigned int period_size, rate;
201 
202 			period_size = ti->substream->runtime->period_size;
203 			rate = ti->substream->runtime->rate;
204 			pos = ti->substream->ops->pointer(ti->substream);
205 			if (pos / period_size != ti->position / period_size) {
206 				ti->need_update = 1;
207 				ti->position = pos;
208 				updates++;
209 			}
210 			pos %= period_size;
211 			pos = period_size - pos;
212 			ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
213 						 rate - 1, rate);
214 		}
215 		if (ti->need_update && !can_update)
216 			min_intr = 0; /* pending to the next irq */
217 		if (ti->frag_count < min_intr)
218 			min_intr = ti->frag_count;
219 	}
220 
221 	if (min_intr < MIN_TICKS)
222 		min_intr = MIN_TICKS;
223 	ct_xfitimer_irq_rearm(atimer, min_intr);
224 	atimer->reprogram = 0; /* clear flag */
225 	return updates;
226 }
227 
228 /* look through the instance list and call period_elapsed if needed */
229 static void ct_xfitimer_check_period(struct ct_timer *atimer)
230 {
231 	struct ct_timer_instance *ti;
232 	unsigned long flags;
233 
234 	spin_lock_irqsave(&atimer->list_lock, flags);
235 	list_for_each_entry(ti, &atimer->instance_head, instance_list) {
236 		if (ti->running && ti->need_update) {
237 			ti->need_update = 0;
238 			ti->apcm->interrupt(ti->apcm);
239 		}
240 	}
241 	spin_unlock_irqrestore(&atimer->list_lock, flags);
242 }
243 
244 /* Handle timer-interrupt */
245 static void ct_xfitimer_callback(struct ct_timer *atimer)
246 {
247 	int update;
248 	unsigned long flags;
249 
250 	spin_lock_irqsave(&atimer->lock, flags);
251 	atimer->irq_handling = 1;
252 	do {
253 		update = ct_xfitimer_reprogram(atimer, 1);
254 		spin_unlock(&atimer->lock);
255 		if (update)
256 			ct_xfitimer_check_period(atimer);
257 		spin_lock(&atimer->lock);
258 	} while (atimer->reprogram);
259 	atimer->irq_handling = 0;
260 	spin_unlock_irqrestore(&atimer->lock, flags);
261 }
262 
263 static void ct_xfitimer_prepare(struct ct_timer_instance *ti)
264 {
265 	ti->frag_count = ti->substream->runtime->period_size;
266 	ti->running = 0;
267 	ti->need_update = 0;
268 }
269 
270 
271 /* start/stop the timer */
272 static void ct_xfitimer_update(struct ct_timer *atimer)
273 {
274 	unsigned long flags;
275 
276 	spin_lock_irqsave(&atimer->lock, flags);
277 	if (atimer->irq_handling) {
278 		/* reached from IRQ handler; let it handle later */
279 		atimer->reprogram = 1;
280 		spin_unlock_irqrestore(&atimer->lock, flags);
281 		return;
282 	}
283 
284 	ct_xfitimer_irq_stop(atimer);
285 	ct_xfitimer_reprogram(atimer, 0);
286 	spin_unlock_irqrestore(&atimer->lock, flags);
287 }
288 
289 static void ct_xfitimer_start(struct ct_timer_instance *ti)
290 {
291 	struct ct_timer *atimer = ti->timer_base;
292 	unsigned long flags;
293 
294 	spin_lock_irqsave(&atimer->lock, flags);
295 	if (list_empty(&ti->running_list))
296 		atimer->wc = ct_xfitimer_get_wc(atimer);
297 	ti->running = 1;
298 	ti->need_update = 0;
299 	list_add(&ti->running_list, &atimer->running_head);
300 	spin_unlock_irqrestore(&atimer->lock, flags);
301 	ct_xfitimer_update(atimer);
302 }
303 
304 static void ct_xfitimer_stop(struct ct_timer_instance *ti)
305 {
306 	struct ct_timer *atimer = ti->timer_base;
307 	unsigned long flags;
308 
309 	spin_lock_irqsave(&atimer->lock, flags);
310 	list_del_init(&ti->running_list);
311 	ti->running = 0;
312 	spin_unlock_irqrestore(&atimer->lock, flags);
313 	ct_xfitimer_update(atimer);
314 }
315 
316 static void ct_xfitimer_free_global(struct ct_timer *atimer)
317 {
318 	ct_xfitimer_irq_stop(atimer);
319 }
320 
321 static const struct ct_timer_ops ct_xfitimer_ops = {
322 	.prepare = ct_xfitimer_prepare,
323 	.start = ct_xfitimer_start,
324 	.stop = ct_xfitimer_stop,
325 	.interrupt = ct_xfitimer_callback,
326 	.free_global = ct_xfitimer_free_global,
327 };
328 
329 /*
330  * timer instance
331  */
332 
333 struct ct_timer_instance *
334 ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm)
335 {
336 	struct ct_timer_instance *ti;
337 
338 	ti = kzalloc(sizeof(*ti), GFP_KERNEL);
339 	if (!ti)
340 		return NULL;
341 	spin_lock_init(&ti->lock);
342 	INIT_LIST_HEAD(&ti->instance_list);
343 	INIT_LIST_HEAD(&ti->running_list);
344 	ti->timer_base = atimer;
345 	ti->apcm = apcm;
346 	ti->substream = apcm->substream;
347 	if (atimer->ops->init)
348 		atimer->ops->init(ti);
349 
350 	spin_lock_irq(&atimer->list_lock);
351 	list_add(&ti->instance_list, &atimer->instance_head);
352 	spin_unlock_irq(&atimer->list_lock);
353 
354 	return ti;
355 }
356 
357 void ct_timer_prepare(struct ct_timer_instance *ti)
358 {
359 	if (ti->timer_base->ops->prepare)
360 		ti->timer_base->ops->prepare(ti);
361 	ti->position = 0;
362 	ti->running = 0;
363 }
364 
365 void ct_timer_start(struct ct_timer_instance *ti)
366 {
367 	struct ct_timer *atimer = ti->timer_base;
368 	atimer->ops->start(ti);
369 }
370 
371 void ct_timer_stop(struct ct_timer_instance *ti)
372 {
373 	struct ct_timer *atimer = ti->timer_base;
374 	atimer->ops->stop(ti);
375 }
376 
377 void ct_timer_instance_free(struct ct_timer_instance *ti)
378 {
379 	struct ct_timer *atimer = ti->timer_base;
380 
381 	atimer->ops->stop(ti); /* to be sure */
382 	if (atimer->ops->free_instance)
383 		atimer->ops->free_instance(ti);
384 
385 	spin_lock_irq(&atimer->list_lock);
386 	list_del(&ti->instance_list);
387 	spin_unlock_irq(&atimer->list_lock);
388 
389 	kfree(ti);
390 }
391 
392 /*
393  * timer manager
394  */
395 
396 static void ct_timer_interrupt(void *data, unsigned int status)
397 {
398 	struct ct_timer *timer = data;
399 
400 	/* Interval timer interrupt */
401 	if ((status & IT_INT) && timer->ops->interrupt)
402 		timer->ops->interrupt(timer);
403 }
404 
405 struct ct_timer *ct_timer_new(struct ct_atc *atc)
406 {
407 	struct ct_timer *atimer;
408 	struct hw *hw;
409 
410 	atimer = kzalloc(sizeof(*atimer), GFP_KERNEL);
411 	if (!atimer)
412 		return NULL;
413 	spin_lock_init(&atimer->lock);
414 	spin_lock_init(&atimer->list_lock);
415 	INIT_LIST_HEAD(&atimer->instance_head);
416 	INIT_LIST_HEAD(&atimer->running_head);
417 	atimer->atc = atc;
418 	hw = atc->hw;
419 	if (!use_system_timer && hw->set_timer_irq) {
420 		dev_info(atc->card->dev, "Use xfi-native timer\n");
421 		atimer->ops = &ct_xfitimer_ops;
422 		hw->irq_callback_data = atimer;
423 		hw->irq_callback = ct_timer_interrupt;
424 	} else {
425 		dev_info(atc->card->dev, "Use system timer\n");
426 		atimer->ops = &ct_systimer_ops;
427 	}
428 	return atimer;
429 }
430 
431 void ct_timer_free(struct ct_timer *atimer)
432 {
433 	struct hw *hw = atimer->atc->hw;
434 	hw->irq_callback = NULL;
435 	if (atimer->ops->free_global)
436 		atimer->ops->free_global(atimer);
437 	kfree(atimer);
438 }
439 
440