Commit 8d3a8b5c authored by Takashi Iwai's avatar Takashi Iwai

ALSA: mixart: Use nonatomic PCM ops

Like the previous patch for VX boards, miXart device driver can be
also rewritten to use nonatomic PCM ops.  Simply spinlocks are
replaced with mutex, the tasklet code is merged into the threaded irq
handler.  Also, now mgr->msg_mutex is superfluous, so merged to
msg_lock.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent db0a5214
...@@ -986,6 +986,7 @@ static int snd_mixart_pcm_analog(struct snd_mixart *chip) ...@@ -986,6 +986,7 @@ static int snd_mixart_pcm_analog(struct snd_mixart *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);
pcm->info_flags = 0; pcm->info_flags = 0;
pcm->nonatomic = true;
strcpy(pcm->name, name); strcpy(pcm->name, name);
preallocate_buffers(chip, pcm); preallocate_buffers(chip, pcm);
...@@ -1018,6 +1019,7 @@ static int snd_mixart_pcm_digital(struct snd_mixart *chip) ...@@ -1018,6 +1019,7 @@ static int snd_mixart_pcm_digital(struct snd_mixart *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_mixart_capture_ops);
pcm->info_flags = 0; pcm->info_flags = 0;
pcm->nonatomic = true;
strcpy(pcm->name, name); strcpy(pcm->name, name);
preallocate_buffers(chip, pcm); preallocate_buffers(chip, pcm);
...@@ -1303,8 +1305,9 @@ static int snd_mixart_probe(struct pci_dev *pci, ...@@ -1303,8 +1305,9 @@ static int snd_mixart_probe(struct pci_dev *pci,
} }
} }
if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED, if (request_threaded_irq(pci->irq, snd_mixart_interrupt,
KBUILD_MODNAME, mgr)) { snd_mixart_threaded_irq, IRQF_SHARED,
KBUILD_MODNAME, mgr)) {
dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq); dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq);
snd_mixart_free(mgr); snd_mixart_free(mgr);
return -EBUSY; return -EBUSY;
...@@ -1314,24 +1317,18 @@ static int snd_mixart_probe(struct pci_dev *pci, ...@@ -1314,24 +1317,18 @@ static int snd_mixart_probe(struct pci_dev *pci,
sprintf(mgr->shortname, "Digigram miXart"); sprintf(mgr->shortname, "Digigram miXart");
sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, irq %i", mgr->shortname, mgr->mem[0].phys, mgr->mem[1].phys, mgr->irq); sprintf(mgr->longname, "%s at 0x%lx & 0x%lx, irq %i", mgr->shortname, mgr->mem[0].phys, mgr->mem[1].phys, mgr->irq);
/* ISR spinlock */
spin_lock_init(&mgr->lock);
/* init mailbox */ /* init mailbox */
mgr->msg_fifo_readptr = 0; mgr->msg_fifo_readptr = 0;
mgr->msg_fifo_writeptr = 0; mgr->msg_fifo_writeptr = 0;
spin_lock_init(&mgr->msg_lock); mutex_init(&mgr->lock);
mutex_init(&mgr->msg_mutex); mutex_init(&mgr->msg_lock);
init_waitqueue_head(&mgr->msg_sleep); init_waitqueue_head(&mgr->msg_sleep);
atomic_set(&mgr->msg_processed, 0); atomic_set(&mgr->msg_processed, 0);
/* init setup mutex*/ /* init setup mutex*/
mutex_init(&mgr->setup_mutex); mutex_init(&mgr->setup_mutex);
/* init message taslket */
tasklet_init(&mgr->msg_taskq, snd_mixart_msg_tasklet, (unsigned long) mgr);
/* card assignment */ /* card assignment */
mgr->num_cards = MIXART_MAX_CARDS; /* 4 FIXME: configurable? */ mgr->num_cards = MIXART_MAX_CARDS; /* 4 FIXME: configurable? */
for (i = 0; i < mgr->num_cards; i++) { for (i = 0; i < mgr->num_cards; i++) {
......
...@@ -78,22 +78,18 @@ struct mixart_mgr { ...@@ -78,22 +78,18 @@ struct mixart_mgr {
char shortname[32]; /* short name of this soundcard */ char shortname[32]; /* short name of this soundcard */
char longname[80]; /* name of this soundcard */ char longname[80]; /* name of this soundcard */
/* message tasklet */
struct tasklet_struct msg_taskq;
/* one and only blocking message or notification may be pending */ /* one and only blocking message or notification may be pending */
u32 pending_event; u32 pending_event;
wait_queue_head_t msg_sleep; wait_queue_head_t msg_sleep;
/* messages stored for tasklet */ /* messages fifo */
u32 msg_fifo[MSG_FIFO_SIZE]; u32 msg_fifo[MSG_FIFO_SIZE];
int msg_fifo_readptr; int msg_fifo_readptr;
int msg_fifo_writeptr; int msg_fifo_writeptr;
atomic_t msg_processed; /* number of messages to be processed in takslet */ atomic_t msg_processed; /* number of messages to be processed in takslet */
spinlock_t lock; /* interrupt spinlock */ struct mutex lock; /* interrupt lock */
spinlock_t msg_lock; /* mailbox spinlock */ struct mutex msg_lock; /* mailbox lock */
struct mutex msg_mutex; /* mutex for blocking_requests */
struct mutex setup_mutex; /* mutex used in hw_params, open and close */ struct mutex setup_mutex; /* mutex used in hw_params, open and close */
......
...@@ -76,7 +76,6 @@ static int retrieve_msg_frame(struct mixart_mgr *mgr, u32 *msg_frame) ...@@ -76,7 +76,6 @@ static int retrieve_msg_frame(struct mixart_mgr *mgr, u32 *msg_frame)
static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp, static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp,
u32 msg_frame_address ) u32 msg_frame_address )
{ {
unsigned long flags;
u32 headptr; u32 headptr;
u32 size; u32 size;
int err; int err;
...@@ -84,7 +83,7 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp, ...@@ -84,7 +83,7 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp,
unsigned int i; unsigned int i;
#endif #endif
spin_lock_irqsave(&mgr->msg_lock, flags); mutex_lock(&mgr->msg_lock);
err = 0; err = 0;
/* copy message descriptor from miXart to driver */ /* copy message descriptor from miXart to driver */
...@@ -133,7 +132,7 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp, ...@@ -133,7 +132,7 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp,
writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD)); writel_be(headptr, MIXART_MEM(mgr, MSG_OUTBOUND_FREE_HEAD));
_clean_exit: _clean_exit:
spin_unlock_irqrestore(&mgr->msg_lock, flags); mutex_unlock(&mgr->msg_lock);
return err; return err;
} }
...@@ -243,28 +242,24 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int ...@@ -243,28 +242,24 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int
wait_queue_t wait; wait_queue_t wait;
long timeout; long timeout;
mutex_lock(&mgr->msg_mutex);
init_waitqueue_entry(&wait, current); init_waitqueue_entry(&wait, current);
spin_lock_irq(&mgr->msg_lock); mutex_lock(&mgr->msg_lock);
/* send the message */ /* send the message */
err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */ err = send_msg(mgr, request, max_resp_size, 1, &msg_frame); /* send and mark the answer pending */
if (err) { if (err) {
spin_unlock_irq(&mgr->msg_lock); mutex_unlock(&mgr->msg_lock);
mutex_unlock(&mgr->msg_mutex);
return err; return err;
} }
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&mgr->msg_sleep, &wait); add_wait_queue(&mgr->msg_sleep, &wait);
spin_unlock_irq(&mgr->msg_lock); mutex_unlock(&mgr->msg_lock);
timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
remove_wait_queue(&mgr->msg_sleep, &wait); remove_wait_queue(&mgr->msg_sleep, &wait);
if (! timeout) { if (! timeout) {
/* error - no ack */ /* error - no ack */
mutex_unlock(&mgr->msg_mutex);
dev_err(&mgr->pci->dev, dev_err(&mgr->pci->dev,
"error: no response on msg %x\n", msg_frame); "error: no response on msg %x\n", msg_frame);
return -EIO; return -EIO;
...@@ -281,7 +276,6 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int ...@@ -281,7 +276,6 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int
if( request->message_id != resp.message_id ) if( request->message_id != resp.message_id )
dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n"); dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n");
mutex_unlock(&mgr->msg_mutex);
return err; return err;
} }
...@@ -300,34 +294,29 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, ...@@ -300,34 +294,29 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr,
if (snd_BUG_ON(notif_event & MSG_CANCEL_NOTIFY_MASK)) if (snd_BUG_ON(notif_event & MSG_CANCEL_NOTIFY_MASK))
return -EINVAL; return -EINVAL;
mutex_lock(&mgr->msg_mutex);
init_waitqueue_entry(&wait, current); init_waitqueue_entry(&wait, current);
spin_lock_irq(&mgr->msg_lock); mutex_lock(&mgr->msg_lock);
/* send the message */ /* send the message */
err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, &notif_event); /* send and mark the notification event pending */ err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 1, &notif_event); /* send and mark the notification event pending */
if(err) { if(err) {
spin_unlock_irq(&mgr->msg_lock); mutex_unlock(&mgr->msg_lock);
mutex_unlock(&mgr->msg_mutex);
return err; return err;
} }
set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&mgr->msg_sleep, &wait); add_wait_queue(&mgr->msg_sleep, &wait);
spin_unlock_irq(&mgr->msg_lock); mutex_unlock(&mgr->msg_lock);
timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES); timeout = schedule_timeout(MSG_TIMEOUT_JIFFIES);
remove_wait_queue(&mgr->msg_sleep, &wait); remove_wait_queue(&mgr->msg_sleep, &wait);
if (! timeout) { if (! timeout) {
/* error - no ack */ /* error - no ack */
mutex_unlock(&mgr->msg_mutex);
dev_err(&mgr->pci->dev, dev_err(&mgr->pci->dev,
"error: notification %x not received\n", notif_event); "error: notification %x not received\n", notif_event);
return -EIO; return -EIO;
} }
mutex_unlock(&mgr->msg_mutex);
return 0; return 0;
} }
...@@ -335,13 +324,12 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, ...@@ -335,13 +324,12 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr,
int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request) int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request)
{ {
u32 message_frame; u32 message_frame;
unsigned long flags;
int err; int err;
/* just send the message (do not mark it as a pending one) */ /* just send the message (do not mark it as a pending one) */
spin_lock_irqsave(&mgr->msg_lock, flags); mutex_lock(&mgr->msg_lock);
err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame); err = send_msg(mgr, request, MSG_DEFAULT_SIZE, 0, &message_frame);
spin_unlock_irqrestore(&mgr->msg_lock, flags); mutex_unlock(&mgr->msg_lock);
/* the answer will be handled by snd_struct mixart_msgasklet() */ /* the answer will be handled by snd_struct mixart_msgasklet() */
atomic_inc(&mgr->msg_processed); atomic_inc(&mgr->msg_processed);
...@@ -350,19 +338,16 @@ int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *requ ...@@ -350,19 +338,16 @@ int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *requ
} }
/* common buffer of tasklet and interrupt to send/receive messages */ /* common buffer of interrupt to send/receive messages */
static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4]; static u32 mixart_msg_data[MSG_DEFAULT_SIZE / 4];
void snd_mixart_msg_tasklet(unsigned long arg) static void snd_mixart_process_msg(struct mixart_mgr *mgr)
{ {
struct mixart_mgr *mgr = ( struct mixart_mgr*)(arg);
struct mixart_msg resp; struct mixart_msg resp;
u32 msg, addr, type; u32 msg, addr, type;
int err; int err;
spin_lock(&mgr->lock);
while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) { while (mgr->msg_fifo_readptr != mgr->msg_fifo_writeptr) {
msg = mgr->msg_fifo[mgr->msg_fifo_readptr]; msg = mgr->msg_fifo[mgr->msg_fifo_readptr];
mgr->msg_fifo_readptr++; mgr->msg_fifo_readptr++;
...@@ -381,7 +366,7 @@ void snd_mixart_msg_tasklet(unsigned long arg) ...@@ -381,7 +366,7 @@ void snd_mixart_msg_tasklet(unsigned long arg)
err = get_msg(mgr, &resp, addr); err = get_msg(mgr, &resp, addr);
if( err < 0 ) { if( err < 0 ) {
dev_err(&mgr->pci->dev, dev_err(&mgr->pci->dev,
"tasklet: error(%d) reading mf %x\n", "error(%d) reading mf %x\n",
err, msg); err, msg);
break; break;
} }
...@@ -393,12 +378,12 @@ void snd_mixart_msg_tasklet(unsigned long arg) ...@@ -393,12 +378,12 @@ void snd_mixart_msg_tasklet(unsigned long arg)
case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET: case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET:
if(mixart_msg_data[0]) if(mixart_msg_data[0])
dev_err(&mgr->pci->dev, dev_err(&mgr->pci->dev,
"tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", "error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n",
mixart_msg_data[0]); mixart_msg_data[0]);
break; break;
default: default:
dev_dbg(&mgr->pci->dev, dev_dbg(&mgr->pci->dev,
"tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n", "received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n",
msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size); msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size);
break; break;
} }
...@@ -409,7 +394,7 @@ void snd_mixart_msg_tasklet(unsigned long arg) ...@@ -409,7 +394,7 @@ void snd_mixart_msg_tasklet(unsigned long arg)
/* get_msg() necessary */ /* get_msg() necessary */
default: default:
dev_err(&mgr->pci->dev, dev_err(&mgr->pci->dev,
"tasklet doesn't know what to do with message %x\n", "doesn't know what to do with message %x\n",
msg); msg);
} /* switch type */ } /* switch type */
...@@ -417,26 +402,17 @@ void snd_mixart_msg_tasklet(unsigned long arg) ...@@ -417,26 +402,17 @@ void snd_mixart_msg_tasklet(unsigned long arg)
atomic_dec(&mgr->msg_processed); atomic_dec(&mgr->msg_processed);
} /* while there is a msg in fifo */ } /* while there is a msg in fifo */
spin_unlock(&mgr->lock);
} }
irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
{ {
struct mixart_mgr *mgr = dev_id; struct mixart_mgr *mgr = dev_id;
int err;
struct mixart_msg resp;
u32 msg;
u32 it_reg; u32 it_reg;
spin_lock(&mgr->lock);
it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET)); it_reg = readl_le(MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET));
if( !(it_reg & MIXART_OIDI) ) { if( !(it_reg & MIXART_OIDI) ) {
/* this device did not cause the interrupt */ /* this device did not cause the interrupt */
spin_unlock(&mgr->lock);
return IRQ_NONE; return IRQ_NONE;
} }
...@@ -450,6 +426,17 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) ...@@ -450,6 +426,17 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
/* clear interrupt */ /* clear interrupt */
writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) ); writel_le( MIXART_OIDI, MIXART_REG(mgr, MIXART_PCI_OMISR_OFFSET) );
return IRQ_WAKE_THREAD;
}
irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id)
{
struct mixart_mgr *mgr = dev_id;
int err;
struct mixart_msg resp;
u32 msg;
mutex_lock(&mgr->lock);
/* process interrupt */ /* process interrupt */
while (retrieve_msg_frame(mgr, &msg)) { while (retrieve_msg_frame(mgr, &msg)) {
...@@ -518,9 +505,9 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) ...@@ -518,9 +505,9 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed ); stream->buf_period_frag = (u32)( sample_count - stream->abs_period_elapsed );
if(elapsed) { if(elapsed) {
spin_unlock(&mgr->lock); mutex_unlock(&mgr->lock);
snd_pcm_period_elapsed(stream->substream); snd_pcm_period_elapsed(stream->substream);
spin_lock(&mgr->lock); mutex_lock(&mgr->lock);
} }
} }
} }
...@@ -556,7 +543,7 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) ...@@ -556,7 +543,7 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
/* no break, continue ! */ /* no break, continue ! */
case MSG_TYPE_ANSWER: case MSG_TYPE_ANSWER:
/* answer or notification to a message we are waiting for*/ /* answer or notification to a message we are waiting for*/
spin_lock(&mgr->msg_lock); mutex_lock(&mgr->msg_lock);
if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) { if( (msg & ~MSG_TYPE_MASK) == mgr->pending_event ) {
wake_up(&mgr->msg_sleep); wake_up(&mgr->msg_sleep);
mgr->pending_event = 0; mgr->pending_event = 0;
...@@ -566,9 +553,9 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) ...@@ -566,9 +553,9 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg; mgr->msg_fifo[mgr->msg_fifo_writeptr] = msg;
mgr->msg_fifo_writeptr++; mgr->msg_fifo_writeptr++;
mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE; mgr->msg_fifo_writeptr %= MSG_FIFO_SIZE;
tasklet_schedule(&mgr->msg_taskq); snd_mixart_process_msg(mgr);
} }
spin_unlock(&mgr->msg_lock); mutex_unlock(&mgr->msg_lock);
break; break;
case MSG_TYPE_REQUEST: case MSG_TYPE_REQUEST:
default: default:
...@@ -582,7 +569,7 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) ...@@ -582,7 +569,7 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
/* allow interrupt again */ /* allow interrupt again */
writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET)); writel_le( MIXART_ALLOW_OUTBOUND_DOORBELL, MIXART_REG( mgr, MIXART_PCI_OMIMR_OFFSET));
spin_unlock(&mgr->lock); mutex_unlock(&mgr->lock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
......
...@@ -564,7 +564,7 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, struct mixart_msg *r ...@@ -564,7 +564,7 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, struct mixart_msg *r
int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request); int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request);
irqreturn_t snd_mixart_interrupt(int irq, void *dev_id); irqreturn_t snd_mixart_interrupt(int irq, void *dev_id);
void snd_mixart_msg_tasklet(unsigned long arg); irqreturn_t snd_mixart_threaded_irq(int irq, void *dev_id);
void snd_mixart_reset_board(struct mixart_mgr *mgr); void snd_mixart_reset_board(struct mixart_mgr *mgr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment