Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: vx: Use nonatomic PCM ops

Rewrite VXpocket and VX222 drivers to use the new PCM nonatomic ops.
The former irq tasklet is replaced with a threaded irq handler, and
the tasklet for the PCM delayed start is simply merged into the normal
PCM trigger, as well as the replacement of spinlock with mutex.

Signed-off-by: Takashi Iwai <tiwai@suse.de>

+78 -109
+2 -5
include/sound/vx_core.h
··· 80 80 81 81 unsigned int references; /* an output pipe may be used for monitoring and/or playback */ 82 82 struct vx_pipe *monitoring_pipe; /* pointer to the monitoring pipe (capture pipe only)*/ 83 - 84 - struct tasklet_struct start_tq; 85 83 }; 86 84 87 85 struct vx_core; ··· 163 165 struct snd_vx_hardware *hw; 164 166 struct snd_vx_ops *ops; 165 167 166 - spinlock_t lock; 167 - spinlock_t irq_lock; 168 - struct tasklet_struct tq; 168 + struct mutex lock; 169 169 170 170 unsigned int chip_status; 171 171 unsigned int pcm_running; ··· 219 223 * interrupt handler; exported for pcmcia 220 224 */ 221 225 irqreturn_t snd_vx_irq_handler(int irq, void *dev); 226 + irqreturn_t snd_vx_threaded_irq_handler(int irq, void *dev); 222 227 223 228 /* 224 229 * lowlevel functions
+23 -26
sound/drivers/vx/vx_core.c
··· 117 117 * 118 118 * returns 0 if successful, or a negative error code. 119 119 * the error code can be VX-specific, retrieved via vx_get_error(). 120 - * NB: call with spinlock held! 120 + * NB: call with mutex held! 121 121 */ 122 122 static int vx_transfer_end(struct vx_core *chip, int cmd) 123 123 { ··· 155 155 * 156 156 * returns 0 if successful, or a negative error code. 157 157 * the error code can be VX-specific, retrieved via vx_get_error(). 158 - * NB: call with spinlock held! 158 + * NB: call with mutex held! 159 159 */ 160 160 static int vx_read_status(struct vx_core *chip, struct vx_rmh *rmh) 161 161 { ··· 236 236 * returns 0 if successful, or a negative error code. 237 237 * the error code can be VX-specific, retrieved via vx_get_error(). 238 238 * 239 - * this function doesn't call spinlock at all. 239 + * this function doesn't call mutex lock at all. 240 240 */ 241 241 int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh) 242 242 { ··· 337 337 338 338 339 339 /* 340 - * vx_send_msg - send a DSP message with spinlock 340 + * vx_send_msg - send a DSP message with mutex 341 341 * @rmh: the rmh record to send and receive 342 342 * 343 343 * returns 0 if successful, or a negative error code. ··· 345 345 */ 346 346 int vx_send_msg(struct vx_core *chip, struct vx_rmh *rmh) 347 347 { 348 - unsigned long flags; 349 348 int err; 350 349 351 - spin_lock_irqsave(&chip->lock, flags); 350 + mutex_lock(&chip->lock); 352 351 err = vx_send_msg_nolock(chip, rmh); 353 - spin_unlock_irqrestore(&chip->lock, flags); 352 + mutex_unlock(&chip->lock); 354 353 return err; 355 354 } 356 355 ··· 361 362 * returns 0 if successful, or a negative error code. 362 363 * the error code can be VX-specific, retrieved via vx_get_error(). 363 364 * 364 - * this function doesn't call spinlock at all. 365 + * this function doesn't call mutex at all. 365 366 * 366 367 * unlike RMH, no command is sent to DSP. 367 368 */ ··· 397 398 398 399 399 400 /* 400 - * vx_send_rih - send an RIH with spinlock 401 + * vx_send_rih - send an RIH with mutex 401 402 * @cmd: the command to send 402 403 * 403 404 * see vx_send_rih_nolock(). 404 405 */ 405 406 int vx_send_rih(struct vx_core *chip, int cmd) 406 407 { 407 - unsigned long flags; 408 408 int err; 409 409 410 - spin_lock_irqsave(&chip->lock, flags); 410 + mutex_lock(&chip->lock); 411 411 err = vx_send_rih_nolock(chip, cmd); 412 - spin_unlock_irqrestore(&chip->lock, flags); 412 + mutex_unlock(&chip->lock); 413 413 return err; 414 414 } 415 415 ··· 480 482 int err; 481 483 482 484 vx_init_rmh(&chip->irq_rmh, CMD_TEST_IT); 483 - spin_lock(&chip->lock); 485 + mutex_lock(&chip->lock); 484 486 err = vx_send_msg_nolock(chip, &chip->irq_rmh); 485 487 if (err < 0) 486 488 *ret = 0; 487 489 else 488 490 *ret = chip->irq_rmh.Stat[0]; 489 - spin_unlock(&chip->lock); 491 + mutex_unlock(&chip->lock); 490 492 return err; 491 493 } 492 494 493 495 494 496 /* 495 - * vx_interrupt - soft irq handler 497 + * snd_vx_threaded_irq_handler - threaded irq handler 496 498 */ 497 - static void vx_interrupt(unsigned long private_data) 499 + irqreturn_t snd_vx_threaded_irq_handler(int irq, void *dev) 498 500 { 499 - struct vx_core *chip = (struct vx_core *) private_data; 501 + struct vx_core *chip = dev; 500 502 unsigned int events; 501 503 502 504 if (chip->chip_status & VX_STAT_IS_STALE) 503 - return; 505 + return IRQ_HANDLED; 504 506 505 507 if (vx_test_irq_src(chip, &events) < 0) 506 - return; 508 + return IRQ_HANDLED; 507 509 508 510 #if 0 509 511 if (events & 0x000800) ··· 517 519 */ 518 520 if (events & FATAL_DSP_ERROR) { 519 521 snd_printk(KERN_ERR "vx_core: fatal DSP error!!\n"); 520 - return; 522 + return IRQ_HANDLED; 521 523 } 522 524 523 525 /* The start on time code conditions are filled (ie the time code ··· 532 534 533 535 /* update the pcm streams */ 534 536 vx_pcm_update_intr(chip, events); 537 + return IRQ_HANDLED; 535 538 } 536 - 539 + EXPORT_SYMBOL(snd_vx_threaded_irq_handler); 537 540 538 541 /** 539 542 * snd_vx_irq_handler - interrupt handler ··· 547 548 (chip->chip_status & VX_STAT_IS_STALE)) 548 549 return IRQ_NONE; 549 550 if (! vx_test_and_ack(chip)) 550 - tasklet_schedule(&chip->tq); 551 - return IRQ_HANDLED; 551 + return IRQ_WAKE_THREAD; 552 + return IRQ_NONE; 552 553 } 553 554 554 555 EXPORT_SYMBOL(snd_vx_irq_handler); ··· 789 790 snd_printk(KERN_ERR "vx_core: no memory\n"); 790 791 return NULL; 791 792 } 792 - spin_lock_init(&chip->lock); 793 - spin_lock_init(&chip->irq_lock); 793 + mutex_init(&chip->lock); 794 794 chip->irq = -1; 795 795 chip->hw = hw; 796 796 chip->type = hw->type; 797 797 chip->ops = ops; 798 - tasklet_init(&chip->tq, vx_interrupt, (unsigned long)chip); 799 798 mutex_init(&chip->mixer_mutex); 800 799 801 800 chip->card = card;
+4 -8
sound/drivers/vx/vx_mixer.c
··· 32 32 */ 33 33 static void vx_write_codec_reg(struct vx_core *chip, int codec, unsigned int data) 34 34 { 35 - unsigned long flags; 36 - 37 35 if (snd_BUG_ON(!chip->ops->write_codec)) 38 36 return; 39 37 40 38 if (chip->chip_status & VX_STAT_IS_STALE) 41 39 return; 42 40 43 - spin_lock_irqsave(&chip->lock, flags); 41 + mutex_lock(&chip->lock); 44 42 chip->ops->write_codec(chip, codec, data); 45 - spin_unlock_irqrestore(&chip->lock, flags); 43 + mutex_unlock(&chip->lock); 46 44 } 47 45 48 46 /* ··· 176 178 */ 177 179 static void vx_change_audio_source(struct vx_core *chip, int src) 178 180 { 179 - unsigned long flags; 180 - 181 181 if (chip->chip_status & VX_STAT_IS_STALE) 182 182 return; 183 183 184 - spin_lock_irqsave(&chip->lock, flags); 184 + mutex_lock(&chip->lock); 185 185 chip->ops->change_audio_source(chip, src); 186 - spin_unlock_irqrestore(&chip->lock, flags); 186 + mutex_unlock(&chip->lock); 187 187 } 188 188 189 189
+23 -45
sound/drivers/vx/vx_pcm.c
··· 229 229 230 230 vx_init_rmh(&rmh, CMD_PIPE_STATE); 231 231 vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); 232 - err = vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 232 + err = vx_send_msg(chip, &rmh); 233 233 if (! err) 234 234 *state = (rmh.Stat[0] & (1 << pipe->number)) ? 1 : 0; 235 235 return err; ··· 280 280 vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); 281 281 rmh.Cmd[0] |= 1; 282 282 283 - err = vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 283 + err = vx_send_msg(chip, &rmh); 284 284 if (! err) { 285 285 if (rmh.Stat[0]) 286 286 err = 1; ··· 300 300 if (pipe->is_capture) 301 301 rmh.Cmd[0] |= COMMAND_RECORD_MASK; 302 302 rmh.Cmd[1] = 1 << pipe->number; 303 - return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 303 + return vx_send_msg(chip, &rmh); 304 304 } 305 305 306 306 /* ··· 311 311 struct vx_rmh rmh; 312 312 313 313 vx_init_rmh(&rmh, CMD_SEND_IRQA); 314 - return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 314 + return vx_send_msg(chip, &rmh); 315 315 } 316 316 317 317 ··· 389 389 struct vx_rmh rmh; 390 390 vx_init_rmh(&rmh, CMD_STOP_PIPE); 391 391 vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); 392 - return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 392 + return vx_send_msg(chip, &rmh); 393 393 } 394 394 395 395 ··· 477 477 vx_init_rmh(&rmh, CMD_START_ONE_STREAM); 478 478 vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number); 479 479 vx_set_differed_time(chip, &rmh, pipe); 480 - return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 480 + return vx_send_msg(chip, &rmh); 481 481 } 482 482 483 483 ··· 492 492 493 493 vx_init_rmh(&rmh, CMD_STOP_STREAM); 494 494 vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number); 495 - return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ 495 + return vx_send_msg(chip, &rmh); 496 496 } 497 497 498 498 ··· 519 519 .fifo_size = 126, 520 520 }; 521 521 522 - 523 - static void vx_pcm_delayed_start(unsigned long arg); 524 522 525 523 /* 526 524 * vx_pcm_playback_open - open callback for playback ··· 551 553 pipe->references++; 552 554 553 555 pipe->substream = subs; 554 - tasklet_init(&pipe->start_tq, vx_pcm_delayed_start, (unsigned long)subs); 555 556 chip->playback_pipes[audio] = pipe; 556 557 557 558 runtime->hw = vx_pcm_playback_hw; ··· 643 646 /* we don't need irqsave here, because this function 644 647 * is called from either trigger callback or irq handler 645 648 */ 646 - spin_lock(&chip->lock); 649 + mutex_lock(&chip->lock); 647 650 vx_pseudo_dma_write(chip, runtime, pipe, size); 648 651 err = vx_notify_end_of_buffer(chip, pipe); 649 652 /* disconnect the host, SIZE_HBUF command always switches to the stream mode */ 650 653 vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT); 651 - spin_unlock(&chip->lock); 654 + mutex_unlock(&chip->lock); 652 655 return err; 653 656 } 654 657 ··· 725 728 } 726 729 727 730 /* 728 - * start the stream and pipe. 729 - * this function is called from tasklet, which is invoked by the trigger 730 - * START callback. 731 - */ 732 - static void vx_pcm_delayed_start(unsigned long arg) 733 - { 734 - struct snd_pcm_substream *subs = (struct snd_pcm_substream *)arg; 735 - struct vx_core *chip = subs->pcm->private_data; 736 - struct vx_pipe *pipe = subs->runtime->private_data; 737 - int err; 738 - 739 - /* printk( KERN_DEBUG "DDDD tasklet delayed start jiffies = %ld\n", jiffies);*/ 740 - 741 - if ((err = vx_start_stream(chip, pipe)) < 0) { 742 - snd_printk(KERN_ERR "vx: cannot start stream\n"); 743 - return; 744 - } 745 - if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0) { 746 - snd_printk(KERN_ERR "vx: cannot start pipe\n"); 747 - return; 748 - } 749 - /* printk( KERN_DEBUG "dddd tasklet delayed start jiffies = %ld \n", jiffies);*/ 750 - } 751 - 752 - /* 753 731 * vx_pcm_playback_trigger - trigger callback for playback 754 732 */ 755 733 static int vx_pcm_trigger(struct snd_pcm_substream *subs, int cmd) ··· 741 769 case SNDRV_PCM_TRIGGER_RESUME: 742 770 if (! pipe->is_capture) 743 771 vx_pcm_playback_transfer(chip, subs, pipe, 2); 744 - /* FIXME: 745 - * we trigger the pipe using tasklet, so that the interrupts are 746 - * issued surely after the trigger is completed. 747 - */ 748 - tasklet_schedule(&pipe->start_tq); 772 + err = vx_start_stream(chip, pipe); 773 + if (err < 0) { 774 + pr_debug("vx: cannot start stream\n"); 775 + return err; 776 + } 777 + err = vx_toggle_pipe(chip, pipe, 1); 778 + if (err < 0) { 779 + pr_debug("vx: cannot start pipe\n"); 780 + vx_stop_stream(chip, pipe); 781 + return err; 782 + } 749 783 chip->pcm_running++; 750 784 pipe->running = 1; 751 785 break; ··· 933 955 if (err < 0) 934 956 return err; 935 957 pipe->substream = subs; 936 - tasklet_init(&pipe->start_tq, vx_pcm_delayed_start, (unsigned long)subs); 937 958 chip->capture_pipes[audio] = pipe; 938 959 939 960 /* check if monitoring is needed */ ··· 1059 1082 count -= 3; 1060 1083 } 1061 1084 /* disconnect the host, SIZE_HBUF command always switches to the stream mode */ 1062 - vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT); 1085 + vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT); 1063 1086 /* read the last pending 6 bytes */ 1064 1087 count = DMA_READ_ALIGN; 1065 1088 while (count > 0) { ··· 1076 1099 1077 1100 _error: 1078 1101 /* disconnect the host, SIZE_HBUF command always switches to the stream mode */ 1079 - vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT); 1102 + vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT); 1080 1103 return; 1081 1104 } 1082 1105 ··· 1252 1275 pcm->private_data = chip; 1253 1276 pcm->private_free = snd_vx_pcm_free; 1254 1277 pcm->info_flags = 0; 1278 + pcm->nonatomic = true; 1255 1279 strcpy(pcm->name, chip->card->shortname); 1256 1280 chip->pcm[i] = pcm; 1257 1281 }
+10 -13
sound/drivers/vx/vx_uer.c
··· 60 60 */ 61 61 static int vx_read_one_cbit(struct vx_core *chip, int index) 62 62 { 63 - unsigned long flags; 64 63 int val; 65 - spin_lock_irqsave(&chip->lock, flags); 64 + 65 + mutex_lock(&chip->lock); 66 66 if (chip->type >= VX_TYPE_VXPOCKET) { 67 67 vx_outb(chip, CSUER, 1); /* read */ 68 68 vx_outb(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK); ··· 72 72 vx_outl(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK); 73 73 val = (vx_inl(chip, RUER) >> 7) & 0x01; 74 74 } 75 - spin_unlock_irqrestore(&chip->lock, flags); 75 + mutex_unlock(&chip->lock); 76 76 return val; 77 77 } 78 78 ··· 83 83 */ 84 84 static void vx_write_one_cbit(struct vx_core *chip, int index, int val) 85 85 { 86 - unsigned long flags; 87 86 val = !!val; /* 0 or 1 */ 88 - spin_lock_irqsave(&chip->lock, flags); 87 + mutex_lock(&chip->lock); 89 88 if (vx_is_pcmcia(chip)) { 90 89 vx_outb(chip, CSUER, 0); /* write */ 91 90 vx_outb(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK)); ··· 92 93 vx_outl(chip, CSUER, 0); /* write */ 93 94 vx_outl(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK)); 94 95 } 95 - spin_unlock_irqrestore(&chip->lock, flags); 96 + mutex_unlock(&chip->lock); 96 97 } 97 98 98 99 /* ··· 189 190 */ 190 191 static void vx_change_clock_source(struct vx_core *chip, int source) 191 192 { 192 - unsigned long flags; 193 - 194 193 /* we mute DAC to prevent clicks */ 195 194 vx_toggle_dac_mute(chip, 1); 196 - spin_lock_irqsave(&chip->lock, flags); 195 + mutex_lock(&chip->lock); 197 196 chip->ops->set_clock_source(chip, source); 198 197 chip->clock_source = source; 199 - spin_unlock_irqrestore(&chip->lock, flags); 198 + mutex_unlock(&chip->lock); 200 199 /* unmute */ 201 200 vx_toggle_dac_mute(chip, 0); 202 201 } ··· 206 209 void vx_set_internal_clock(struct vx_core *chip, unsigned int freq) 207 210 { 208 211 int clock; 209 - unsigned long flags; 212 + 210 213 /* Get real clock value */ 211 214 clock = vx_calc_clock_from_freq(chip, freq); 212 215 snd_printdd(KERN_DEBUG "set internal clock to 0x%x from freq %d\n", clock, freq); 213 - spin_lock_irqsave(&chip->lock, flags); 216 + mutex_lock(&chip->lock); 214 217 if (vx_is_pcmcia(chip)) { 215 218 vx_outb(chip, HIFREQ, (clock >> 8) & 0x0f); 216 219 vx_outb(chip, LOFREQ, clock & 0xff); ··· 218 221 vx_outl(chip, HIFREQ, (clock >> 8) & 0x0f); 219 222 vx_outl(chip, LOFREQ, clock & 0xff); 220 223 } 221 - spin_unlock_irqrestore(&chip->lock, flags); 224 + mutex_unlock(&chip->lock); 222 225 } 223 226 224 227
+3 -2
sound/pci/vx222/vx222.c
··· 168 168 for (i = 0; i < 2; i++) 169 169 vx->port[i] = pci_resource_start(pci, i + 1); 170 170 171 - if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED, 172 - KBUILD_MODNAME, chip)) { 171 + if (request_threaded_irq(pci->irq, snd_vx_irq_handler, 172 + snd_vx_threaded_irq_handler, IRQF_SHARED, 173 + KBUILD_MODNAME, chip)) { 173 174 dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); 174 175 snd_vx222_free(chip); 175 176 return -EBUSY;
+4 -6
sound/pcmcia/vx/vxp_ops.c
··· 468 468 void vx_set_mic_boost(struct vx_core *chip, int boost) 469 469 { 470 470 struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; 471 - unsigned long flags; 472 471 473 472 if (chip->chip_status & VX_STAT_IS_STALE) 474 473 return; 475 474 476 - spin_lock_irqsave(&chip->lock, flags); 475 + mutex_lock(&chip->lock); 477 476 if (pchip->regCDSP & P24_CDSP_MICS_SEL_MASK) { 478 477 if (boost) { 479 478 /* boost: 38 dB */ ··· 485 486 } 486 487 vx_outb(chip, CDSP, pchip->regCDSP); 487 488 } 488 - spin_unlock_irqrestore(&chip->lock, flags); 489 + mutex_unlock(&chip->lock); 489 490 } 490 491 491 492 /* ··· 510 511 void vx_set_mic_level(struct vx_core *chip, int level) 511 512 { 512 513 struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; 513 - unsigned long flags; 514 514 515 515 if (chip->chip_status & VX_STAT_IS_STALE) 516 516 return; 517 517 518 - spin_lock_irqsave(&chip->lock, flags); 518 + mutex_lock(&chip->lock); 519 519 if (pchip->regCDSP & VXP_CDSP_MIC_SEL_MASK) { 520 520 level = vx_compute_mic_level(level); 521 521 vx_outb(chip, MICRO, level); 522 522 } 523 - spin_unlock_irqrestore(&chip->lock, flags); 523 + mutex_unlock(&chip->lock); 524 524 } 525 525 526 526
+9 -4
sound/pcmcia/vx/vxpocket.c
··· 62 62 */ 63 63 static void vxpocket_release(struct pcmcia_device *link) 64 64 { 65 + free_irq(link->irq, link->priv); 65 66 pcmcia_disable_device(link); 66 67 } 67 68 ··· 228 227 229 228 ret = pcmcia_request_io(link); 230 229 if (ret) 231 - goto failed; 230 + goto failed_preirq; 232 231 233 - ret = pcmcia_request_irq(link, snd_vx_irq_handler); 232 + ret = request_threaded_irq(link->irq, snd_vx_irq_handler, 233 + snd_vx_threaded_irq_handler, 234 + IRQF_SHARED, link->devname, link->priv); 234 235 if (ret) 235 - goto failed; 236 + goto failed_preirq; 236 237 237 238 ret = pcmcia_enable_device(link); 238 239 if (ret) ··· 248 245 249 246 return 0; 250 247 251 - failed: 248 + failed: 249 + free_irq(link->irq, link->priv); 250 + failed_preirq: 252 251 pcmcia_disable_device(link); 253 252 return -ENODEV; 254 253 }