Commit 19890e58 authored by Hiroshi DOYU's avatar Hiroshi DOYU Committed by Tony Lindgren

ARM: OMAP: Restructuring mailbox blk queues

Signed-off-by: default avatarTrilok Soni <soni.trilok@gmail.com>
Signed-off-by: default avatarHiroshi DOYU <Hiroshi.DOYU@nokia.com>
Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent fcff08de
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#ifndef DRIVER_DSP_COMMON_H #ifndef DRIVER_DSP_COMMON_H
#define DRIVER_DSP_COMMON_H #define DRIVER_DSP_COMMON_H
#include <linux/clk.h>
#include "hardware_dsp.h" #include "hardware_dsp.h"
#define DSPSPACE_SIZE 0x1000000 #define DSPSPACE_SIZE 0x1000000
......
...@@ -339,14 +339,14 @@ int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg, ...@@ -339,14 +339,14 @@ int dsp_mbcmd_send_and_wait_exarg(struct mbcmd *mb, struct mb_exarg *arg,
/* /*
* mbcmd receiver * mbcmd receiver
*/ */
static void mbcmd_receiver(mbox_msg_t msg) static int mbcmd_receiver(void *data)
{ {
struct mbcmd *mb = (struct mbcmd *)&msg; struct mbcmd *mb = data;
if (cmdinfo[mb->cmd_h] == NULL) { if (cmdinfo[mb->cmd_h] == NULL) {
printk(KERN_ERR printk(KERN_ERR
"invalid message (%08x) for mbcmd_receiver().\n", msg); "invalid message for mbcmd_receiver().\n");
return; return -EINVAL;
} }
(*mbseq_expect)++; (*mbseq_expect)++;
...@@ -359,6 +359,7 @@ static void mbcmd_receiver(mbox_msg_t msg) ...@@ -359,6 +359,7 @@ static void mbcmd_receiver(mbox_msg_t msg)
else else
printk(KERN_ERR "mbox: %s is not allowed from DSP.\n", printk(KERN_ERR "mbox: %s is not allowed from DSP.\n",
cmd_name(*mb)); cmd_name(*mb));
return 0;
} }
static int mbsync_hold_mem_active; static int mbsync_hold_mem_active;
...@@ -411,16 +412,16 @@ static int __init dsp_mbox_init(void) ...@@ -411,16 +412,16 @@ static int __init dsp_mbox_init(void)
return -ENODEV; return -ENODEV;
} }
omap_dsp->mbox->msg_receive_cb = mbcmd_receiver; omap_dsp->mbox->rxq->callback = mbcmd_receiver;
omap_dsp->mbox->msg_sender_cb = mbcmd_sender_prepare; omap_dsp->mbox->txq->callback = mbcmd_sender_prepare;
return 0; return 0;
} }
static void dsp_mbox_exit(void) static void dsp_mbox_exit(void)
{ {
omap_dsp->mbox->msg_sender_cb = NULL; omap_dsp->mbox->rxq->callback = NULL;
omap_dsp->mbox->msg_receive_cb = NULL; omap_dsp->mbox->txq->callback = NULL;
if (mbsync_hold_mem_active) { if (mbsync_hold_mem_active) {
dsp_mem_disable((void *)daram_base); dsp_mem_disable((void *)daram_base);
......
...@@ -59,8 +59,8 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg) ...@@ -59,8 +59,8 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg)
udelay(1); udelay(1);
} }
if (mbox->msg_sender_cb && arg) { if (arg && mbox->txq->callback) {
ret = mbox->msg_sender_cb(arg); ret = mbox->txq->callback(arg);
if (ret) if (ret)
goto out; goto out;
} }
...@@ -74,78 +74,113 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg) ...@@ -74,78 +74,113 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg)
int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg) int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg)
{ {
struct request *rq; struct request *rq;
struct request_queue *q = mbox->txq->queue;
int ret = 0; int ret = 0;
rq = blk_get_request(mbox->txq, WRITE, GFP_ATOMIC); rq = blk_get_request(q, WRITE, GFP_ATOMIC);
if (unlikely(!rq)) { if (unlikely(!rq)) {
ret = -ENOMEM; ret = -ENOMEM;
goto fail; goto fail;
} }
rq->data = (void *)msg; rq->data = (void *)msg;
blk_insert_request(mbox->txq, rq, 0, arg); blk_insert_request(q, rq, 0, arg);
schedule_work(&mbox->txq->work);
fail: fail:
return ret; return ret;
} }
EXPORT_SYMBOL(omap_mbox_msg_send); EXPORT_SYMBOL(omap_mbox_msg_send);
static void mbox_tx_work(struct work_struct *work)
{
int ret;
struct request *rq;
struct omap_mbox_queue *mq = container_of(work, struct omap_mbox_queue, work);
struct omap_mbox *mbox = mq->queue->queuedata;
struct request_queue *q = mbox->txq->queue;
while (1) {
spin_lock(q->queue_lock);
rq = elv_next_request(q);
spin_unlock(q->queue_lock);
if (!rq)
break;
ret = __mbox_msg_send(mbox, (mbox_msg_t) rq->data, rq->special);
if (ret) {
enable_mbox_irq(mbox, IRQ_TX);
return;
}
spin_lock(q->queue_lock);
blkdev_dequeue_request(rq);
end_that_request_last(rq, 0);
spin_unlock(q->queue_lock);
}
}
/* /*
* Message receiver(workqueue) * Message receiver(workqueue)
*/ */
static void mbox_msg_receiver(struct work_struct *work) static void mbox_rx_work(struct work_struct *work)
{ {
struct omap_mbox *mbox = struct omap_mbox_queue *mq = container_of(work, struct omap_mbox_queue, work);
container_of(work, struct omap_mbox, msg_receive); struct omap_mbox *mbox = mq->queue->queuedata;
struct request_queue *q = mbox->rxq; struct request_queue *q = mbox->rxq->queue;
struct request *rq; struct request *rq;
mbox_msg_t msg; mbox_msg_t msg;
unsigned long flags;
if (mbox->msg_receive_cb == NULL) { if (mbox->rxq->callback == NULL) {
sysfs_notify(&mbox->dev.kobj, NULL, "mbox"); sysfs_notify(&mbox->dev.kobj, NULL, "mbox");
return; return;
} }
while (1) { while (1) {
spin_lock_irqsave(q->queue_lock, flags);
rq = elv_next_request(q); rq = elv_next_request(q);
spin_unlock_irqrestore(q->queue_lock, flags);
if (!rq) if (!rq)
break; break;
msg = (mbox_msg_t)rq->data; msg = (mbox_msg_t) rq->data;
spin_lock_irqsave(q->queue_lock, flags);
blkdev_dequeue_request(rq); blkdev_dequeue_request(rq);
end_that_request_last(rq, 0); end_that_request_last(rq, 0);
spin_unlock_irqrestore(q->queue_lock, flags);
if (mbox->msg_receive_cb) mbox->rxq->callback((void *)msg);
mbox->msg_receive_cb(msg);
} }
} }
/* /*
* Mailbox interrupt handler * Mailbox interrupt handler
*/ */
static void mbox_txq_fn(request_queue_t *q) static void mbox_txq_fn(request_queue_t * q)
{ {
struct omap_mbox *mbox = q->queuedata; }
int ret;
struct request *rq;
while ((rq = elv_next_request(q)) != NULL) { static void mbox_rxq_fn(request_queue_t * q)
ret = __mbox_msg_send(mbox, (mbox_msg_t)rq->data, rq->special); {
if (ret) {
blk_stop_queue(q);
enable_mbox_irq(mbox, IRQ_TX);
return;
}
blkdev_dequeue_request(rq);
end_that_request_last(rq, 0);
}
} }
static void mbox_rxq_fn(request_queue_t *q) static void __mbox_tx_interrupt(struct omap_mbox *mbox)
{
disable_mbox_irq(mbox, IRQ_TX);
ack_mbox_irq(mbox, IRQ_TX);
schedule_work(&mbox->txq->work);
}
static void __mbox_rx_interrupt(struct omap_mbox *mbox)
{ {
struct request *rq; struct request *rq;
struct omap_mbox *mbox = q->queuedata;
mbox_msg_t msg; mbox_msg_t msg;
request_queue_t *q = mbox->rxq->queue;
disable_mbox_irq(mbox, IRQ_RX);
while (!mbox_fifo_empty(mbox)) { while (!mbox_fifo_empty(mbox)) {
rq = blk_get_request(q, WRITE, GFP_ATOMIC); rq = blk_get_request(q, WRITE, GFP_ATOMIC);
...@@ -161,7 +196,7 @@ static void mbox_rxq_fn(request_queue_t *q) ...@@ -161,7 +196,7 @@ static void mbox_rxq_fn(request_queue_t *q)
mbox->err_notify(); mbox->err_notify();
} }
blk_insert_request(mbox->rxq, rq, 0, NULL); blk_insert_request(q, rq, 0, NULL);
if (mbox->ops->type == OMAP_MBOX_TYPE1) if (mbox->ops->type == OMAP_MBOX_TYPE1)
break; break;
} }
...@@ -169,24 +204,19 @@ static void mbox_rxq_fn(request_queue_t *q) ...@@ -169,24 +204,19 @@ static void mbox_rxq_fn(request_queue_t *q)
/* no more messages in the fifo. clear IRQ source. */ /* no more messages in the fifo. clear IRQ source. */
ack_mbox_irq(mbox, IRQ_RX); ack_mbox_irq(mbox, IRQ_RX);
enable_mbox_irq(mbox, IRQ_RX); enable_mbox_irq(mbox, IRQ_RX);
nomem: nomem:
queue_work(mbox->workq, &mbox->msg_receive); schedule_work(&mbox->rxq->work);
} }
static irqreturn_t mbox_interrupt(int irq, void *p) static irqreturn_t mbox_interrupt(int irq, void *p)
{ {
struct omap_mbox *mbox = (struct omap_mbox *)p; struct omap_mbox *mbox = (struct omap_mbox *)p;
if (is_mbox_irq(mbox, IRQ_TX)) { if (is_mbox_irq(mbox, IRQ_TX))
disable_mbox_irq(mbox, IRQ_TX); __mbox_tx_interrupt(mbox);
ack_mbox_irq(mbox, IRQ_TX);
blk_start_queue(mbox->txq);
}
if (is_mbox_irq(mbox, IRQ_RX)) { if (is_mbox_irq(mbox, IRQ_RX))
disable_mbox_irq(mbox, IRQ_RX); __mbox_rx_interrupt(mbox);
blk_start_queue(mbox->rxq);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -213,18 +243,28 @@ omap_mbox_write(struct device *dev, struct device_attribute *attr, ...@@ -213,18 +243,28 @@ omap_mbox_write(struct device *dev, struct device_attribute *attr,
} }
static ssize_t static ssize_t
omap_mbox_read(struct device *dev, struct device_attribute *attr, omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf)
char * buf)
{ {
unsigned long flags;
struct request *rq; struct request *rq;
mbox_msg_t *p = (mbox_msg_t *)buf; mbox_msg_t *p = (mbox_msg_t *) buf;
struct omap_mbox *mbox = dev_get_drvdata(dev); struct omap_mbox *mbox = dev_get_drvdata(dev);
struct request_queue *q = mbox->rxq; struct request_queue *q = mbox->rxq->queue;
while (1) {
spin_lock_irqsave(q->queue_lock, flags);
rq = elv_next_request(q);
spin_unlock_irqrestore(q->queue_lock, flags);
if (!rq)
break;
while ((rq = elv_next_request(q)) != NULL) { *p = (mbox_msg_t) rq->data;
*p = (mbox_msg_t)rq->data;
spin_lock_irqsave(q->queue_lock, flags);
blkdev_dequeue_request(rq); blkdev_dequeue_request(rq);
end_that_request_last(rq, 0); end_that_request_last(rq, 0);
spin_unlock_irqrestore(q->queue_lock, flags);
if (unlikely(mbox_seq_test(mbox, *p))) { if (unlikely(mbox_seq_test(mbox, *p))) {
pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p); pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p);
...@@ -235,7 +275,7 @@ omap_mbox_read(struct device *dev, struct device_attribute *attr, ...@@ -235,7 +275,7 @@ omap_mbox_read(struct device *dev, struct device_attribute *attr,
pr_debug("%02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]); pr_debug("%02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]);
return (size_t)((char *)p - buf); return (size_t) ((char *)p - buf);
} }
static DEVICE_ATTR(mbox, S_IRUGO | S_IWUSR, omap_mbox_read, omap_mbox_write); static DEVICE_ATTR(mbox, S_IRUGO | S_IWUSR, omap_mbox_read, omap_mbox_write);
...@@ -251,10 +291,43 @@ static struct class omap_mbox_class = { ...@@ -251,10 +291,43 @@ static struct class omap_mbox_class = {
.name = "omap_mbox", .name = "omap_mbox",
}; };
static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
request_fn_proc * proc,
void (*work) (struct work_struct *))
{
request_queue_t *q;
struct omap_mbox_queue *mq;
mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
if (!mq)
return NULL;
spin_lock_init(&mq->lock);
q = blk_init_queue(proc, &mq->lock);
if (!q)
goto error;
q->queuedata = mbox;
mq->queue = q;
INIT_WORK(&mq->work, work);
return mq;
error:
kfree(mq);
return NULL;
}
static void mbox_queue_free(struct omap_mbox_queue *q)
{
blk_cleanup_queue(q->queue);
kfree(q);
}
static int omap_mbox_init(struct omap_mbox *mbox) static int omap_mbox_init(struct omap_mbox *mbox)
{ {
int ret; int ret;
request_queue_t *q; struct omap_mbox_queue *mq;
if (likely(mbox->ops->startup)) { if (likely(mbox->ops->startup)) {
ret = mbox->ops->startup(mbox); ret = mbox->ops->startup(mbox);
...@@ -277,9 +350,6 @@ static int omap_mbox_init(struct omap_mbox *mbox) ...@@ -277,9 +350,6 @@ static int omap_mbox_init(struct omap_mbox *mbox)
goto fail_create_mbox; goto fail_create_mbox;
} }
spin_lock_init(&mbox->lock);
INIT_WORK(&mbox->msg_receive, mbox_msg_receiver);
ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED, ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED,
mbox->name, mbox); mbox->name, mbox);
if (unlikely(ret)) { if (unlikely(ret)) {
...@@ -289,23 +359,25 @@ static int omap_mbox_init(struct omap_mbox *mbox) ...@@ -289,23 +359,25 @@ static int omap_mbox_init(struct omap_mbox *mbox)
} }
enable_mbox_irq(mbox, IRQ_RX); enable_mbox_irq(mbox, IRQ_RX);
q = blk_init_queue(mbox_txq_fn, &mbox->lock); mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work);
if (!q) if (!mq) {
goto fail_blkinit_txq; ret = -ENOMEM;
mbox->txq = q; goto fail_alloc_txq;
q->queuedata = mbox; }
mbox->txq = mq;
q = blk_init_queue(mbox_rxq_fn, &mbox->lock); mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work);
if (!q) if (!mq) {
goto fail_blkinit_rxq; ret = -ENOMEM;
mbox->rxq = q; goto fail_alloc_rxq;
q->queuedata = mbox; }
mbox->rxq = mq;
return 0; return 0;
fail_blkinit_rxq: fail_alloc_rxq:
blk_cleanup_queue(mbox->txq); mbox_queue_free(mbox->txq);
fail_blkinit_txq: fail_alloc_txq:
free_irq(mbox->irq, mbox); free_irq(mbox->irq, mbox);
fail_request_irq: fail_request_irq:
device_remove_file(&mbox->dev, &dev_attr_mbox); device_remove_file(&mbox->dev, &dev_attr_mbox);
...@@ -320,11 +392,8 @@ static int omap_mbox_init(struct omap_mbox *mbox) ...@@ -320,11 +392,8 @@ static int omap_mbox_init(struct omap_mbox *mbox)
static void omap_mbox_fini(struct omap_mbox *mbox) static void omap_mbox_fini(struct omap_mbox *mbox)
{ {
blk_cleanup_queue(mbox->txq); mbox_queue_free(mbox->txq);
blk_cleanup_queue(mbox->rxq); mbox_queue_free(mbox->rxq);
flush_workqueue(mbox->workq);
destroy_workqueue(mbox->workq);
free_irq(mbox->irq, mbox); free_irq(mbox->irq, mbox);
device_remove_file(&mbox->dev, &dev_attr_mbox); device_remove_file(&mbox->dev, &dev_attr_mbox);
...@@ -349,7 +418,6 @@ static struct omap_mbox **find_mboxes(const char *name) ...@@ -349,7 +418,6 @@ static struct omap_mbox **find_mboxes(const char *name)
struct omap_mbox *omap_mbox_get(const char *name) struct omap_mbox *omap_mbox_get(const char *name)
{ {
struct omap_mbox *mbox; struct omap_mbox *mbox;
char queue_name[MBOX_NAME_LEN];
int ret; int ret;
read_lock(&mboxes_lock); read_lock(&mboxes_lock);
...@@ -359,10 +427,6 @@ struct omap_mbox *omap_mbox_get(const char *name) ...@@ -359,10 +427,6 @@ struct omap_mbox *omap_mbox_get(const char *name)
return ERR_PTR(-ENOENT); return ERR_PTR(-ENOENT);
} }
strcpy(queue_name, "mailbox/");
strcat(queue_name, mbox->name);
mbox->workq = create_singlethread_workqueue(queue_name);
read_unlock(&mboxes_lock); read_unlock(&mboxes_lock);
ret = omap_mbox_init(mbox); ret = omap_mbox_init(mbox);
......
...@@ -35,18 +35,19 @@ struct omap_mbox_ops { ...@@ -35,18 +35,19 @@ struct omap_mbox_ops {
int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq); int (*is_irq)(struct omap_mbox *mbox, omap_mbox_irq_t irq);
}; };
struct omap_mbox_queue {
spinlock_t lock;
request_queue_t *queue;
struct work_struct work;
int (*callback)(void *);
struct omap_mbox *mbox;
};
struct omap_mbox { struct omap_mbox {
char *name; char *name;
spinlock_t lock;
unsigned int irq; unsigned int irq;
struct workqueue_struct *workq; struct omap_mbox_queue *txq, *rxq;
struct work_struct msg_receive;
request_queue_t *txq, *rxq;
void (*msg_receive_cb)(mbox_msg_t);
int (*msg_sender_cb)(void*);
struct omap_mbox_ops *ops; struct omap_mbox_ops *ops;
......
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