Update of /cvsroot/alsa/alsa-kernel/pci/mixart In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28667/pci/mixart
Modified Files: mixart.c mixart.h mixart_core.c Log Message: - fixed the race condition in message flow. - removed obsolete debug prints. - make prepare callback non-atomic. - synchronize with the pending messages in prepare and hw_free callbacks. Index: mixart.c =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/pci/mixart/mixart.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- mixart.c 23 Feb 2004 18:18:23 -0000 1.3 +++ mixart.c 24 Feb 2004 12:08:03 -0000 1.4 @@ -123,12 +123,8 @@ request.size = sizeof(group_state); err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp); - if(err) { - snd_printk(KERN_ERR "error MSG_STREAM_ST***_STREAM_GRP_PACKET\n"); - return err; - } - if(group_state_resp.txx_status != 0) { - snd_printk(KERN_ERR "error status MSG_STREAM_ST***_STREAM_GRP_PACKET (%x)!\n", group_state_resp.txx_status); + if (err < 0 || group_state_resp.txx_status != 0) { + snd_printk(KERN_ERR "error MSG_STREAM_ST***_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status); return -EINVAL; } @@ -138,13 +134,9 @@ group_state.pipe_count = 0; /* in case of start same command once again with pipe_count=0 */ err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp); - if(err) { - snd_printk(KERN_ERR "error MSG_STREAM_START_STREAM_GRP_PACKET !\n"); - return err; - } - if(group_state_resp.txx_status != 0) { - snd_printk(KERN_ERR "error status MSG_STREAM_START_STREAM_GRP_PACKET (%x)!\n", group_state_resp.txx_status); - return -EINVAL; + if (err < 0 || group_state_resp.txx_status != 0) { + snd_printk(KERN_ERR "error MSG_STREAM_START_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status); + return -EINVAL; } /* in case of start send a synchro top */ @@ -155,12 +147,9 @@ request.size = 0; err = snd_mixart_send_msg(mgr, &request, sizeof(stat), &stat); - if(err) { - snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD!\n"); - return err; - } - if(stat) { - snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD stat=%x!\n", stat); + if (err < 0 || stat != 0) { + snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD err=%x stat=%x !\n", err, stat); + return -EINVAL; } pipe->status = PIPE_RUNNING; @@ -176,6 +165,8 @@ { mixart_msg_t request; mixart_clock_properties_t clock_properties; + mixart_clock_properties_resp_t clock_prop_resp; + int err; switch(pipe->status) { case PIPE_CLOCK_SET: @@ -206,13 +197,16 @@ request.data = &clock_properties; request.size = sizeof(clock_properties); - /* we are not allowed to wait for the response, so simply set rate */ - /* TODO : error has to be handled later in the tasklet! */ + err = snd_mixart_send_msg(mgr, &request, sizeof(clock_prop_resp), &clock_prop_resp); + if (err < 0 || clock_prop_resp.status != 0 || clock_prop_resp.clock_mode != CM_STANDALONE) { + snd_printk(KERN_ERR "error MSG_CLOCK_SET_PROPERTIES err=%x stat=%x mod=%x !\n", err, clock_prop_resp.status, clock_prop_resp.clock_mode); + return -EINVAL; + } if(rate) pipe->status = PIPE_CLOCK_SET; else pipe->status = PIPE_RUNNING; - return snd_mixart_send_msg_nonblock(mgr, &request); + return 0; } @@ -295,7 +289,7 @@ err = snd_mixart_send_msg(chip->mgr, &request, sizeof(streaming_group_resp), &streaming_group_resp); if((err < 0) || (streaming_group_resp.status != 0)) { - snd_printk(KERN_ERR "message MSG_STREAM_ADD_**PUT_GROUP return error: err(%x) status(%x)!\n", err, streaming_group_resp.status); + snd_printk(KERN_ERR "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n", err, streaming_group_resp.status); return NULL; } @@ -406,7 +400,6 @@ snd_printdd("SNDRV_PCM_TRIGGER_START\n"); - // snd_printk(KERN_DEBUG "hw_avail = %d\n", snd_pcm_playback_hw_avail(subs->runtime)); /* START_STREAM */ if( mixart_set_stream_state(stream, 1) ) return -EINVAL; @@ -420,7 +413,6 @@ if( mixart_set_stream_state(stream, 0) ) return -EINVAL; - /* TODO : mixart drains data transefered in advance -> mute stream ? */ stream->status = MIXART_STREAM_STATUS_OPEN; snd_printdd("SNDRV_PCM_TRIGGER_STOP\n"); @@ -443,8 +435,24 @@ return 0; } +static int mixart_sync_nonblock_events(mixart_mgr_t *mgr) +{ + int timeout = HZ; + while (atomic_read(&mgr->msg_processed) > 0) { + if (! timeout--) { + snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n"); + return -EBUSY; + } + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + return 0; +} + /* * prepare callback for all pcms + * + * NOTE: this callback is non-atomic (pcm->info_flags |= SNDRV_PCM_INFO_NONATOMIC_OPS) */ static int snd_mixart_prepare(snd_pcm_substream_t *subs) { @@ -455,6 +463,8 @@ snd_printdd("snd_mixart_prepare\n"); + mixart_sync_nonblock_events(chip->mgr); + /* only the first stream can choose the sample rate */ /* the further opened streams will be limited to its frequency (see open) */ if(chip->mgr->ref_count_rate == 1) @@ -519,9 +529,8 @@ stream_param.sample_size = 32; break; default: - snd_printk(KERN_DEBUG "error use default SNDRV_PCM_FORMAT_S16_LE\n"); - stream_param.sample_type = ST_INTEGER_16LE; - stream_param.sample_size = 16; + snd_printk(KERN_ERR "error mixart_set_format() : unknown format\n"); + return -EINVAL; } snd_printdd("set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n", @@ -544,7 +553,7 @@ err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp); if((err < 0) || resp.error_code) { - snd_printk(KERN_DEBUG "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code); + snd_printk(KERN_ERR "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code); return -EINVAL; } return 0; @@ -586,7 +595,6 @@ /* set the format to the board */ err = mixart_set_format(stream, format); if(err < 0) { - snd_printk(KERN_DEBUG "mixart_set_format() returned error (%x)\n", err); return err; } @@ -611,7 +619,9 @@ static int snd_mixart_hw_free(snd_pcm_substream_t *subs) { + mixart_t *chip = snd_pcm_substream_chip(subs); snd_pcm_lib_free_pages(subs); + mixart_sync_nonblock_events(chip->mgr); return 0; } @@ -916,7 +926,7 @@ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops); - pcm->info_flags = 0; + pcm->info_flags = SNDRV_PCM_INFO_NONATOMIC_OPS; strcpy(pcm->name, name); preallocate_buffers(chip, pcm); @@ -947,7 +957,7 @@ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_mixart_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops); - pcm->info_flags = 0; + pcm->info_flags = SNDRV_PCM_INFO_NONATOMIC_OPS; strcpy(pcm->name, name); preallocate_buffers(chip, pcm); @@ -1318,6 +1328,8 @@ mgr->msg_lock = SPIN_LOCK_UNLOCKED; init_MUTEX(&mgr->msg_mutex); + init_waitqueue_head(&mgr->msg_sleep); + atomic_set(&mgr->msg_processed, 0); /* init setup mutex*/ init_MUTEX(&mgr->setup_mutex); Index: mixart.h =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/pci/mixart/mixart.h,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- mixart.h 9 Feb 2004 17:40:48 -0000 1.1 +++ mixart.h 24 Feb 2004 12:08:03 -0000 1.2 @@ -102,6 +102,7 @@ u32 msg_fifo[MSG_FIFO_SIZE]; int msg_fifo_readptr; int msg_fifo_writeptr; + atomic_t msg_processed; /* number of messages to be processed in takslet */ spinlock_t lock; /* interrupt spinlock */ spinlock_t msg_lock; /* mailbox spinlock */ Index: mixart_core.c =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/pci/mixart/mixart_core.c,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- mixart_core.c 23 Feb 2004 18:18:24 -0000 1.3 +++ mixart_core.c 24 Feb 2004 12:08:03 -0000 1.4 @@ -132,20 +132,19 @@ /* * send a message to miXart. return: the msg_frame used for this message */ +/* call with mgr->msg_lock held! */ static int send_msg( mixart_mgr_t *mgr, mixart_msg_t *msg, int max_answersize, int mark_pending, u32 *msg_event) { - unsigned long flags; u32 headptr, tailptr; u32 msg_frame_address; int err, i; snd_assert(msg->size % 4 == 0, return -EINVAL); - spin_lock_irqsave(&mgr->msg_lock, flags); err = 0; /* get message frame address */ @@ -154,13 +153,11 @@ if (tailptr == headptr) { snd_printk(KERN_ERR "error: no message frame available\n"); - err = -EBUSY; - goto _clean_exit; + return -EBUSY; } if( (tailptr < MSG_INBOUND_FREE_STACK) || (tailptr >= (MSG_INBOUND_FREE_STACK+MSG_BOUND_STACK_SIZE))) { - err = -EINVAL; - goto _clean_exit; + return -EINVAL; } msg_frame_address = readl_be(MIXART_MEM(mgr, tailptr)); @@ -213,8 +210,7 @@ headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD)); if( (headptr < MSG_INBOUND_POST_STACK) || (headptr >= (MSG_INBOUND_POST_STACK+MSG_BOUND_STACK_SIZE))) { - err = -EINVAL; - goto _clean_exit; + return -EINVAL; } writel_be(msg_frame_address, MIXART_MEM(mgr, headptr)); @@ -226,8 +222,6 @@ writel_be(headptr, MIXART_MEM(mgr, MSG_INBOUND_POST_HEAD)); - _clean_exit: - spin_unlock_irqrestore(&mgr->msg_lock, flags); return 0; } @@ -242,23 +236,21 @@ down(&mgr->msg_mutex); - init_waitqueue_head(&mgr->msg_sleep); init_waitqueue_entry(&wait, current); - current->state = TASK_UNINTERRUPTIBLE; - add_wait_queue(&mgr->msg_sleep, &wait); - + spin_lock_irq(&mgr->msg_lock); /* send the message */ err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */ - if(err) { - current->state = TASK_RUNNING; - remove_wait_queue(&mgr->msg_sleep, &wait); + if (err) { + spin_unlock_irq(&mgr->msg_lock); up(&mgr->msg_mutex); return err; } + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&mgr->msg_sleep, &wait); + spin_unlock_irq(&mgr->msg_lock); timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); - current->state = TASK_RUNNING; remove_wait_queue(&mgr->msg_sleep, &wait); if (! timeout) { @@ -296,23 +288,21 @@ down(&mgr->msg_mutex); - init_waitqueue_head(&mgr->msg_sleep); init_waitqueue_entry(&wait, current); - current->state = TASK_UNINTERRUPTIBLE; - add_wait_queue(&mgr->msg_sleep, &wait); - + spin_lock_irq(&mgr->msg_lock); /* send the message */ err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, ¬if_event); /* send and mark the notification event pending */ if(err) { - current->state = TASK_RUNNING; - remove_wait_queue(&mgr->msg_sleep, &wait); + spin_unlock_irq(&mgr->msg_lock); up(&mgr->msg_mutex); return err; } + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&mgr->msg_sleep, &wait); + spin_unlock_irq(&mgr->msg_lock); timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); - current->state = TASK_RUNNING; remove_wait_queue(&mgr->msg_sleep, &wait); if (! timeout) { @@ -330,11 +320,18 @@ int snd_mixart_send_msg_nonblock(mixart_mgr_t *mgr, mixart_msg_t *request) { u32 message_frame; + unsigned long flags; + int err; /* just send the message (do not mark it as a pending one) */ - return send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame); + spin_lock_irqsave(&mgr->msg_lock, flags); + err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame); + spin_unlock_irqrestore(&mgr->msg_lock, flags); /* the answer will be handled by snd_mixart_msg_tasklet() */ + atomic_inc(&mgr->msg_processed); + + return err; } @@ -378,16 +375,7 @@ case MSG_STREAM_STOP_INPUT_STAGE_PACKET: case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET: if(mixart_msg_data[0]) - snd_printdd("tasklet : MSG_STREAM_ST***_***PUT_STAGE_PACKET txx_status(%x)\n", mixart_msg_data[0]); - break; - case MSG_CLOCK_CHECK_PROPERTIES: - case MSG_CLOCK_SET_PROPERTIES: - if(mixart_msg_data[0]) - snd_printdd("tasklet : MSG_CLOCK_***_PROPERTIES txx_status(%x) clock_mode(%x)\n", mixart_msg_data[0], mixart_msg_data[1]); - break; - case MSG_SYSTEM_WAIT_SYNCHRO_CMD: - if(mixart_msg_data[0]) - snd_printdd("tasklet : MSG_SYSTEM_WAIT_SYNCHRO_CMD txx_status(%x)\n", mixart_msg_data[0]); + snd_printk(KERN_ERR "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", mixart_msg_data[0]); break; default: snd_printdd("tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%d)\n", @@ -395,13 +383,17 @@ break; } break; - case MSG_TYPE_NOTIFY: + case MSG_TYPE_NOTIFY: /* msg contains no address ! do not get_msg() ! */ case MSG_TYPE_COMMAND: /* get_msg() necessary */ default: snd_printk(KERN_ERR "tasklet doesn't know what to do with message %x\n", msg); } /* switch type */ + + /* decrement counter */ + atomic_dec(&mgr->msg_processed); + } /* while there is a msg in fifo */ spin_unlock(&mgr->lock); @@ -466,7 +458,8 @@ mixart_stream_t *stream; if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) { - snd_printk(KERN_DEBUG "ERROR buffer_id (%x) pos(%d)\n", buffer_id, notify->streams[i].sample_pos_low_part); + snd_printk(KERN_ERR "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n", + buffer_id, notify->streams[i].sample_pos_low_part); break; } @@ -533,6 +526,7 @@ /* no break, continue ! */ case MSG_TYPE_ANSWER: /* answer or notification to a message we are waiting for*/ + spin_lock(&mgr->msg_lock); if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) { wake_up(&mgr->msg_sleep); mgr->pending_event = 0; @@ -544,6 +538,7 @@ mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE; tasklet_hi_schedule(&mgr->msg_taskq); } + spin_unlock(&mgr->msg_lock); break; case MSG_TYPE_REQUEST: default: ------------------------------------------------------- SF.Net is sponsored by: Speed Start Your Linux Apps Now. Build and deploy apps & Web services for Linux with a free DVD software kit from IBM. Click Now! http://ads.osdn.com/?ad_id=1356&alloc_id=3438&op=click _______________________________________________ Alsa-cvslog mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/alsa-cvslog