aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ctxfi
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2009-06-08 04:21:07 -0400
committerTakashi Iwai <tiwai@suse.de>2009-06-08 06:38:54 -0400
commit54de6bc8b2437f642844cecb8d183df2368ffceb (patch)
tree6b984265d3da7ba6d11d7fb53a7e84b8d3485e1d /sound/pci/ctxfi
parent28cd4aa43de2b6d3b1e3385d450bfb31cbe8d72a (diff)
ALSA: ctxfi - Optimize the native timer handling using wc counter
Optimize the timer update routine to look up wall clock once instead of checking the position of each stream at each timer update. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/ctxfi')
-rw-r--r--sound/pci/ctxfi/cthardware.h1
-rw-r--r--sound/pci/ctxfi/cthw20k1.c6
-rw-r--r--sound/pci/ctxfi/cttimer.c76
3 files changed, 55 insertions, 28 deletions
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h
index 35350cf9d2f2..8f11644ddc92 100644
--- a/sound/pci/ctxfi/cthardware.h
+++ b/sound/pci/ctxfi/cthardware.h
@@ -147,6 +147,7 @@ struct hw {
147 147
148 int (*set_timer_irq)(struct hw *hw, int enable); 148 int (*set_timer_irq)(struct hw *hw, int enable);
149 int (*set_timer_tick)(struct hw *hw, unsigned int tick); 149 int (*set_timer_tick)(struct hw *hw, unsigned int tick);
150 unsigned int (*get_wc)(struct hw *hw);
150 151
151 void (*irq_callback)(void *data, unsigned int bit); 152 void (*irq_callback)(void *data, unsigned int bit);
152 void *irq_callback_data; 153 void *irq_callback_data;
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c
index df565c11fcca..b165466e1a54 100644
--- a/sound/pci/ctxfi/cthw20k1.c
+++ b/sound/pci/ctxfi/cthw20k1.c
@@ -1186,6 +1186,11 @@ static int set_timer_tick(struct hw *hw, unsigned int ticks)
1186 return 0; 1186 return 0;
1187} 1187}
1188 1188
1189static unsigned int get_wc(struct hw *hw)
1190{
1191 return hw_read_20kx(hw, WC);
1192}
1193
1189/* Card hardware initialization block */ 1194/* Card hardware initialization block */
1190struct dac_conf { 1195struct dac_conf {
1191 unsigned int msr; /* master sample rate in rsrs */ 1196 unsigned int msr; /* master sample rate in rsrs */
@@ -2235,6 +2240,7 @@ static struct hw ct20k1_preset __devinitdata = {
2235 2240
2236 .set_timer_irq = set_timer_irq, 2241 .set_timer_irq = set_timer_irq,
2237 .set_timer_tick = set_timer_tick, 2242 .set_timer_tick = set_timer_tick,
2243 .get_wc = get_wc,
2238}; 2244};
2239 2245
2240int __devinit create_20k1_hw_obj(struct hw **rhw) 2246int __devinit create_20k1_hw_obj(struct hw **rhw)
diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c
index ceda74e356cb..ec869a4fe2b3 100644
--- a/sound/pci/ctxfi/cttimer.c
+++ b/sound/pci/ctxfi/cttimer.c
@@ -47,6 +47,7 @@ struct ct_timer {
47 struct ct_timer_ops *ops; 47 struct ct_timer_ops *ops;
48 struct list_head instance_head; 48 struct list_head instance_head;
49 struct list_head running_head; 49 struct list_head running_head;
50 unsigned int wc; /* current wallclock */
50 unsigned int irq_handling:1; /* in IRQ handling */ 51 unsigned int irq_handling:1; /* in IRQ handling */
51 unsigned int reprogram:1; /* need to reprogram the internval */ 52 unsigned int reprogram:1; /* need to reprogram the internval */
52 unsigned int running:1; /* global timer running */ 53 unsigned int running:1; /* global timer running */
@@ -136,6 +137,7 @@ static struct ct_timer_ops ct_systimer_ops = {
136 */ 137 */
137 138
138#define CT_TIMER_FREQ 48000 139#define CT_TIMER_FREQ 48000
140#define MIN_TICKS 1
139#define MAX_TICKS ((1 << 13) - 1) 141#define MAX_TICKS ((1 << 13) - 1)
140 142
141static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks) 143static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks)
@@ -159,6 +161,12 @@ static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
159 } 161 }
160} 162}
161 163
164static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer)
165{
166 struct hw *hw = atimer->atc->hw;
167 return hw->get_wc(hw);
168}
169
162/* 170/*
163 * reprogram the timer interval; 171 * reprogram the timer interval;
164 * checks the running instance list and determines the next timer interval. 172 * checks the running instance list and determines the next timer interval.
@@ -170,37 +178,46 @@ static void ct_xfitimer_irq_stop(struct ct_timer *atimer)
170static int ct_xfitimer_reprogram(struct ct_timer *atimer) 178static int ct_xfitimer_reprogram(struct ct_timer *atimer)
171{ 179{
172 struct ct_timer_instance *ti; 180 struct ct_timer_instance *ti;
173 int min_intr = -1; 181 unsigned int min_intr = (unsigned int)-1;
174 int updates = 0; 182 int updates = 0;
183 unsigned int wc, diff;
175 184
185 if (list_empty(&atimer->running_head)) {
186 ct_xfitimer_irq_stop(atimer);
187 atimer->reprogram = 0; /* clear flag */
188 return 0;
189 }
190
191 wc = ct_xfitimer_get_wc(atimer);
192 diff = wc - atimer->wc;
193 atimer->wc = wc;
176 list_for_each_entry(ti, &atimer->running_head, running_list) { 194 list_for_each_entry(ti, &atimer->running_head, running_list) {
177 struct snd_pcm_runtime *runtime; 195 if (ti->frag_count > diff)
178 unsigned int pos, diff; 196 ti->frag_count -= diff;
179 int intr; 197 else {
180 runtime = ti->substream->runtime; 198 unsigned int pos;
181 pos = ti->substream->ops->pointer(ti->substream); 199 unsigned int period_size, rate;
182 if (pos < ti->position) 200
183 diff = runtime->buffer_size - ti->position + pos; 201 period_size = ti->substream->runtime->period_size;
184 else 202 rate = ti->substream->runtime->rate;
185 diff = pos - ti->position; 203 pos = ti->substream->ops->pointer(ti->substream);
186 ti->position = pos; 204 if (pos / period_size != ti->position / period_size) {
187 while (diff >= ti->frag_count) { 205 ti->need_update = 1;
188 ti->frag_count += runtime->period_size; 206 ti->position = pos;
189 ti->need_update = 1; 207 updates++;
190 updates++; 208 }
209 pos %= period_size;
210 pos = period_size - pos;
211 ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ +
212 rate - 1, rate);
191 } 213 }
192 ti->frag_count -= diff; 214 if (ti->frag_count < min_intr)
193 intr = div_u64((u64)ti->frag_count * CT_TIMER_FREQ, 215 min_intr = ti->frag_count;
194 runtime->rate);
195 if (min_intr < 0 || intr < min_intr)
196 min_intr = intr;
197 } 216 }
198 217
199 if (min_intr > 0) 218 if (min_intr < MIN_TICKS)
200 ct_xfitimer_irq_rearm(atimer, min_intr); 219 min_intr = MIN_TICKS;
201 else 220 ct_xfitimer_irq_rearm(atimer, min_intr);
202 ct_xfitimer_irq_stop(atimer);
203
204 atimer->reprogram = 0; /* clear flag */ 221 atimer->reprogram = 0; /* clear flag */
205 return updates; 222 return updates;
206} 223}
@@ -253,13 +270,14 @@ static void ct_xfitimer_update(struct ct_timer *atimer)
253 unsigned long flags; 270 unsigned long flags;
254 int update; 271 int update;
255 272
273 spin_lock_irqsave(&atimer->lock, flags);
256 if (atimer->irq_handling) { 274 if (atimer->irq_handling) {
257 /* reached from IRQ handler; let it handle later */ 275 /* reached from IRQ handler; let it handle later */
258 atimer->reprogram = 1; 276 atimer->reprogram = 1;
277 spin_unlock_irqrestore(&atimer->lock, flags);
259 return; 278 return;
260 } 279 }
261 280
262 spin_lock_irqsave(&atimer->lock, flags);
263 ct_xfitimer_irq_stop(atimer); 281 ct_xfitimer_irq_stop(atimer);
264 update = ct_xfitimer_reprogram(atimer); 282 update = ct_xfitimer_reprogram(atimer);
265 spin_unlock_irqrestore(&atimer->lock, flags); 283 spin_unlock_irqrestore(&atimer->lock, flags);
@@ -273,6 +291,8 @@ static void ct_xfitimer_start(struct ct_timer_instance *ti)
273 unsigned long flags; 291 unsigned long flags;
274 292
275 spin_lock_irqsave(&atimer->lock, flags); 293 spin_lock_irqsave(&atimer->lock, flags);
294 if (list_empty(&ti->running_list))
295 atimer->wc = ct_xfitimer_get_wc(atimer);
276 list_add(&ti->running_list, &atimer->running_head); 296 list_add(&ti->running_list, &atimer->running_head);
277 spin_unlock_irqrestore(&atimer->lock, flags); 297 spin_unlock_irqrestore(&atimer->lock, flags);
278 ct_xfitimer_update(atimer); 298 ct_xfitimer_update(atimer);
@@ -396,12 +416,12 @@ struct ct_timer *ct_timer_new(struct ct_atc *atc)
396 atimer->atc = atc; 416 atimer->atc = atc;
397 hw = atc->hw; 417 hw = atc->hw;
398 if (!USE_SYSTEM_TIMER && hw->set_timer_irq) { 418 if (!USE_SYSTEM_TIMER && hw->set_timer_irq) {
399 printk(KERN_INFO "ctxfi: Use xfi-native timer\n"); 419 snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n");
400 atimer->ops = &ct_xfitimer_ops; 420 atimer->ops = &ct_xfitimer_ops;
401 hw->irq_callback_data = atimer; 421 hw->irq_callback_data = atimer;
402 hw->irq_callback = ct_timer_interrupt; 422 hw->irq_callback = ct_timer_interrupt;
403 } else { 423 } else {
404 printk(KERN_INFO "ctxfi: Use system timer\n"); 424 snd_printd(KERN_INFO "ctxfi: Use system timer\n");
405 atimer->ops = &ct_systimer_ops; 425 atimer->ops = &ct_systimer_ops;
406 } 426 }
407 return atimer; 427 return atimer;