diff options
author | Hari Kanigeri <h-kanigeri2@ti.com> | 2010-08-05 21:00:01 -0400 |
---|---|---|
committer | Paolo Pisati <paolo.pisati@canonical.com> | 2012-08-17 04:19:06 -0400 |
commit | 28e00e987cf585247a88b4efc764c2892089f1bd (patch) | |
tree | 884a4c57629a484529710fc09c9ef2731ede0825 | |
parent | 3bdbdae464566dd88236e27e04d0ce677a9e30ba (diff) |
omap:mailbox-resolve multiple receiver problem
The ISR is handling only the mailbox instance that was registered last.
So if both mailbox instances are running at the same time, the first mailbox
that registered wouldn't get the mailbox message. The same issue is present
in Transmit Interrupt case too. Only the last registered mailbox is handled.
The fix is to iterate through the list of mailbox that were registered.
Signed-off-by: Hari Kanigeri <h-kanigeri2@ti.com>
Signed-off-by: Ramesh Gupta <grgupta@ti.com>
Signed-off-by: Subramaniam C.A <subramaniam.ca@ti.com>
-rw-r--r-- | arch/arm/plat-omap/mailbox.c | 66 |
1 files changed, 44 insertions, 22 deletions
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index 578465de17a..faadfb6cb5a 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c | |||
@@ -167,37 +167,59 @@ static void mbox_rx_work(struct work_struct *work) | |||
167 | */ | 167 | */ |
168 | static void __mbox_tx_interrupt(struct omap_mbox *mbox) | 168 | static void __mbox_tx_interrupt(struct omap_mbox *mbox) |
169 | { | 169 | { |
170 | omap_mbox_disable_irq(mbox, IRQ_TX); | 170 | struct omap_mbox *mbox_curr; |
171 | ack_mbox_irq(mbox, IRQ_TX); | 171 | int i =0; |
172 | tasklet_schedule(&mbox->txq->tasklet); | 172 | |
173 | while (mboxes[i]) { | ||
174 | mbox_curr = mboxes[i]; | ||
175 | if (!mbox_fifo_full(mbox_curr)) { | ||
176 | omap_mbox_disable_irq(mbox_curr, IRQ_TX); | ||
177 | ack_mbox_irq(mbox_curr, IRQ_TX); | ||
178 | tasklet_schedule(&mbox_curr->txq->tasklet); | ||
179 | } | ||
180 | i++; | ||
181 | } | ||
173 | } | 182 | } |
174 | 183 | ||
175 | static void __mbox_rx_interrupt(struct omap_mbox *mbox) | 184 | static void __mbox_rx_interrupt(struct omap_mbox *mbox) |
176 | { | 185 | { |
177 | struct omap_mbox_queue *mq = mbox->rxq; | 186 | struct omap_mbox_queue *mq; |
178 | mbox_msg_t msg; | 187 | mbox_msg_t msg; |
179 | int len; | 188 | int len; |
180 | 189 | int i = 0; | |
181 | while (!mbox_fifo_empty(mbox)) { | 190 | struct omap_mbox *mbox_curr; |
182 | if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { | 191 | bool msg_rx; |
183 | omap_mbox_disable_irq(mbox, IRQ_RX); | 192 | |
184 | mq->full = true; | 193 | while (mboxes[i]) { |
185 | goto nomem; | 194 | mbox_curr = mboxes[i]; |
195 | mq = mbox_curr->rxq; | ||
196 | msg_rx = false; | ||
197 | while (!mbox_fifo_empty(mbox_curr)) { | ||
198 | msg_rx = true; | ||
199 | if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) { | ||
200 | omap_mbox_disable_irq(mbox_curr, IRQ_RX); | ||
201 | rq_full = true; | ||
202 | goto nomem; | ||
203 | } | ||
204 | |||
205 | msg = mbox_fifo_read(mbox_curr); | ||
206 | |||
207 | len = kfifo_in(&mq->fifo, (unsigned char *)&msg, | ||
208 | sizeof(msg)); | ||
209 | if (unlikely(len != sizeof(msg))) | ||
210 | pr_err("%s: kfifo_in anomaly detected\n", | ||
211 | __func__); | ||
212 | if (mbox->ops->type == OMAP_MBOX_TYPE1) | ||
213 | break; | ||
186 | } | 214 | } |
215 | /* no more messages in the fifo. clear IRQ source. */ | ||
216 | if (msg_rx) | ||
217 | ack_mbox_irq(mbox, IRQ_RX); | ||
218 | nomem: | ||
219 | schedule_work(&mbox->rxq->work); | ||
187 | 220 | ||
188 | msg = mbox_fifo_read(mbox); | 221 | i++; |
189 | |||
190 | len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg)); | ||
191 | WARN_ON(len != sizeof(msg)); | ||
192 | |||
193 | if (mbox->ops->type == OMAP_MBOX_TYPE1) | ||
194 | break; | ||
195 | } | 222 | } |
196 | |||
197 | /* no more messages in the fifo. clear IRQ source. */ | ||
198 | ack_mbox_irq(mbox, IRQ_RX); | ||
199 | nomem: | ||
200 | schedule_work(&mbox->rxq->work); | ||
201 | } | 223 | } |
202 | 224 | ||
203 | static irqreturn_t mbox_interrupt(int irq, void *p) | 225 | static irqreturn_t mbox_interrupt(int irq, void *p) |