aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2008-11-05 23:15:41 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-30 06:38:02 -0500
commit72c2d6d3ac91d1b9efb482ff4a8dd68e3d867965 (patch)
tree0e80f865ac4763e30eb7777360fbf3d860b140f0 /drivers/media/video/cx18
parentf68d0cf56761128e85ebc98d8de4776b89c30279 (diff)
V4L/DVB (9593): cx18: Add outgoing mailbox mutexes and check for ack via waitq vs poll
Add mutexes to ensure exclusive access for outgoing driver to CX23418 mailboxes. Also wait on a waitq for mailbox acknowledgement from the CX23418 instead of polling. Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx18')
-rw-r--r--drivers/media/video/cx18/cx18-driver.c4
-rw-r--r--drivers/media/video/cx18/cx18-driver.h7
-rw-r--r--drivers/media/video/cx18/cx18-irq.c21
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c84
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.h7
5 files changed, 60 insertions, 63 deletions
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 6799eab8b6ac..3079e466e6e7 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -446,6 +446,8 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
446 mutex_init(&cx->i2c_bus_lock[0]); 446 mutex_init(&cx->i2c_bus_lock[0]);
447 mutex_init(&cx->i2c_bus_lock[1]); 447 mutex_init(&cx->i2c_bus_lock[1]);
448 mutex_init(&cx->gpio_lock); 448 mutex_init(&cx->gpio_lock);
449 mutex_init(&cx->epu2apu_mb_lock);
450 mutex_init(&cx->epu2cpu_mb_lock);
449 451
450 spin_lock_init(&cx->lock); 452 spin_lock_init(&cx->lock);
451 453
@@ -466,8 +468,6 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
466 init_waitqueue_head(&cx->cap_w); 468 init_waitqueue_head(&cx->cap_w);
467 init_waitqueue_head(&cx->mb_apu_waitq); 469 init_waitqueue_head(&cx->mb_apu_waitq);
468 init_waitqueue_head(&cx->mb_cpu_waitq); 470 init_waitqueue_head(&cx->mb_cpu_waitq);
469 init_waitqueue_head(&cx->mb_epu_waitq);
470 init_waitqueue_head(&cx->mb_hpu_waitq);
471 init_waitqueue_head(&cx->dma_waitq); 471 init_waitqueue_head(&cx->dma_waitq);
472 472
473 /* VBI */ 473 /* VBI */
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index 04f1c624da7c..e2ec15549783 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -378,7 +378,10 @@ struct cx18 {
378 u32 v4l2_cap; /* V4L2 capabilities of card */ 378 u32 v4l2_cap; /* V4L2 capabilities of card */
379 u32 hw_flags; /* Hardware description of the board */ 379 u32 hw_flags; /* Hardware description of the board */
380 unsigned mdl_offset; 380 unsigned mdl_offset;
381 struct cx18_scb __iomem *scb; /* pointer to SCB */ 381 struct cx18_scb __iomem *scb; /* pointer to SCB */
382 struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/
383 struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/
384
382 385
383 struct cx18_av_state av_state; 386 struct cx18_av_state av_state;
384 387
@@ -428,8 +431,6 @@ struct cx18 {
428 431
429 wait_queue_head_t mb_apu_waitq; 432 wait_queue_head_t mb_apu_waitq;
430 wait_queue_head_t mb_cpu_waitq; 433 wait_queue_head_t mb_cpu_waitq;
431 wait_queue_head_t mb_epu_waitq;
432 wait_queue_head_t mb_hpu_waitq;
433 wait_queue_head_t cap_w; 434 wait_queue_head_t cap_w;
434 /* when the current DMA is finished this queue is woken up */ 435 /* when the current DMA is finished this queue is woken up */
435 wait_queue_head_t dma_waitq; 436 wait_queue_head_t dma_waitq;
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c
index 33f56c61ca74..37b931055d3a 100644
--- a/drivers/media/video/cx18/cx18-irq.c
+++ b/drivers/media/video/cx18/cx18-irq.c
@@ -38,7 +38,7 @@ void cx18_work_handler(struct work_struct *work)
38 cx18_dvb_work_handler(cx); 38 cx18_dvb_work_handler(cx);
39} 39}
40 40
41static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) 41static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb, int rpu)
42{ 42{
43 u32 handle = mb->args[0]; 43 u32 handle = mb->args[0];
44 struct cx18_stream *s = NULL; 44 struct cx18_stream *s = NULL;
@@ -59,7 +59,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
59 " handle %d\n", handle); 59 " handle %d\n", handle);
60 mb->error = CXERR_NOT_OPEN; 60 mb->error = CXERR_NOT_OPEN;
61 mb->cmd = 0; 61 mb->cmd = 0;
62 cx18_mb_ack(cx, mb); 62 cx18_mb_ack(cx, mb, rpu);
63 return; 63 return;
64 } 64 }
65 65
@@ -86,13 +86,13 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
86 } 86 }
87 mb->error = 0; 87 mb->error = 0;
88 mb->cmd = 0; 88 mb->cmd = 0;
89 cx18_mb_ack(cx, mb); 89 cx18_mb_ack(cx, mb, rpu);
90 wake_up(&cx->dma_waitq); 90 wake_up(&cx->dma_waitq);
91 if (s->id != -1) 91 if (s->id != -1)
92 wake_up(&s->waitq); 92 wake_up(&s->waitq);
93} 93}
94 94
95static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb) 95static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb, int rpu)
96{ 96{
97 char str[256] = { 0 }; 97 char str[256] = { 0 };
98 char *p; 98 char *p;
@@ -102,7 +102,7 @@ static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb)
102 cx18_memcpy_fromio(cx, str, cx->enc_mem + mb->args[1], 252); 102 cx18_memcpy_fromio(cx, str, cx->enc_mem + mb->args[1], 252);
103 str[252] = 0; 103 str[252] = 0;
104 } 104 }
105 cx18_mb_ack(cx, mb); 105 cx18_mb_ack(cx, mb, rpu);
106 CX18_DEBUG_INFO("%x %s\n", mb->args[0], str); 106 CX18_DEBUG_INFO("%x %s\n", mb->args[0], str);
107 p = strchr(str, '.'); 107 p = strchr(str, '.');
108 if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) 108 if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
@@ -119,10 +119,10 @@ static void epu_cmd(struct cx18 *cx, u32 sw1)
119 119
120 switch (mb.cmd) { 120 switch (mb.cmd) {
121 case CX18_EPU_DMA_DONE: 121 case CX18_EPU_DMA_DONE:
122 epu_dma_done(cx, &mb); 122 epu_dma_done(cx, &mb, CPU);
123 break; 123 break;
124 case CX18_EPU_DEBUG: 124 case CX18_EPU_DEBUG:
125 epu_debug(cx, &mb); 125 epu_debug(cx, &mb, CPU);
126 break; 126 break;
127 default: 127 default:
128 CX18_WARN("Unknown CPU_TO_EPU mailbox command %#08x\n", 128 CX18_WARN("Unknown CPU_TO_EPU mailbox command %#08x\n",
@@ -135,11 +135,6 @@ static void epu_cmd(struct cx18 *cx, u32 sw1)
135 cx18_memcpy_fromio(cx, &mb, &cx->scb->apu2epu_mb, sizeof(mb)); 135 cx18_memcpy_fromio(cx, &mb, &cx->scb->apu2epu_mb, sizeof(mb));
136 CX18_WARN("Unknown APU_TO_EPU mailbox command %#08x\n", mb.cmd); 136 CX18_WARN("Unknown APU_TO_EPU mailbox command %#08x\n", mb.cmd);
137 } 137 }
138
139 if (sw1 & IRQ_HPU_TO_EPU) {
140 cx18_memcpy_fromio(cx, &mb, &cx->scb->hpu2epu_mb, sizeof(mb));
141 CX18_WARN("Unknown HPU_TO_EPU mailbox command %#08x\n", mb.cmd);
142 }
143} 138}
144 139
145static void xpu_ack(struct cx18 *cx, u32 sw2) 140static void xpu_ack(struct cx18 *cx, u32 sw2)
@@ -148,8 +143,6 @@ static void xpu_ack(struct cx18 *cx, u32 sw2)
148 wake_up(&cx->mb_cpu_waitq); 143 wake_up(&cx->mb_cpu_waitq);
149 if (sw2 & IRQ_APU_TO_EPU_ACK) 144 if (sw2 & IRQ_APU_TO_EPU_ACK)
150 wake_up(&cx->mb_apu_waitq); 145 wake_up(&cx->mb_apu_waitq);
151 if (sw2 & IRQ_HPU_TO_EPU_ACK)
152 wake_up(&cx->mb_hpu_waitq);
153} 146}
154 147
155irqreturn_t cx18_irq_handler(int irq, void *dev_id) 148irqreturn_t cx18_irq_handler(int irq, void *dev_id)
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index acff7dfb60df..d2975a2e6cb7 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -30,11 +30,6 @@
30#define API_FAST (1 << 2) /* Short timeout */ 30#define API_FAST (1 << 2) /* Short timeout */
31#define API_SLOW (1 << 3) /* Additional 300ms timeout */ 31#define API_SLOW (1 << 3) /* Additional 300ms timeout */
32 32
33#define APU 0
34#define CPU 1
35#define EPU 2
36#define HPU 3
37
38struct cx18_api_info { 33struct cx18_api_info {
39 u32 cmd; 34 u32 cmd;
40 u8 flags; /* Flags, see above */ 35 u8 flags; /* Flags, see above */
@@ -117,10 +112,7 @@ static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu
117 *irq = cx18_readl(cx, &cx->scb->epu2cpu_irq); 112 *irq = cx18_readl(cx, &cx->scb->epu2cpu_irq);
118 break; 113 break;
119 114
120 case HPU: 115 default:
121 mb = &cx->scb->epu2hpu_mb;
122 *state = cx18_readl(cx, &cx->scb->hpu_state);
123 *irq = cx18_readl(cx, &cx->scb->epu2hpu_irq);
124 break; 116 break;
125 } 117 }
126 118
@@ -142,25 +134,12 @@ static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu
142 return NULL; 134 return NULL;
143} 135}
144 136
145long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) 137long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb, int rpu)
146{ 138{
147 const struct cx18_api_info *info = find_api_info(mb->cmd);
148 struct cx18_mailbox __iomem *ack_mb; 139 struct cx18_mailbox __iomem *ack_mb;
149 u32 ack_irq; 140 u32 ack_irq;
150 u8 rpu = CPU;
151
152 if (info == NULL && mb->cmd) {
153 CX18_WARN("Cannot ack unknown command %x\n", mb->cmd);
154 return -EINVAL;
155 }
156 if (info)
157 rpu = info->rpu;
158 141
159 switch (rpu) { 142 switch (rpu) {
160 case HPU:
161 ack_irq = IRQ_EPU_TO_HPU_ACK;
162 ack_mb = &cx->scb->hpu2epu_mb;
163 break;
164 case APU: 143 case APU:
165 ack_irq = IRQ_EPU_TO_APU_ACK; 144 ack_irq = IRQ_EPU_TO_APU_ACK;
166 ack_mb = &cx->scb->apu2epu_mb; 145 ack_mb = &cx->scb->apu2epu_mb;
@@ -170,7 +149,8 @@ long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
170 ack_mb = &cx->scb->cpu2epu_mb; 149 ack_mb = &cx->scb->cpu2epu_mb;
171 break; 150 break;
172 default: 151 default:
173 CX18_WARN("Unknown RPU for command %x\n", mb->cmd); 152 CX18_WARN("Unhandled RPU (%d) for command %x ack\n",
153 rpu, mb->cmd);
174 return -EINVAL; 154 return -EINVAL;
175 } 155 }
176 156
@@ -187,8 +167,8 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
187 u32 state = 0, irq = 0, req, oldreq, err; 167 u32 state = 0, irq = 0, req, oldreq, err;
188 struct cx18_mailbox __iomem *mb; 168 struct cx18_mailbox __iomem *mb;
189 wait_queue_head_t *waitq; 169 wait_queue_head_t *waitq;
170 struct mutex *mb_lock;
190 int timeout = 100; 171 int timeout = 100;
191 int cnt = 0;
192 int sig = 0; 172 int sig = 0;
193 int i; 173 int i;
194 174
@@ -201,10 +181,27 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
201 CX18_DEBUG_HI_API("%s\n", info->name); 181 CX18_DEBUG_HI_API("%s\n", info->name);
202 else 182 else
203 CX18_DEBUG_API("%s\n", info->name); 183 CX18_DEBUG_API("%s\n", info->name);
184
185 switch (info->rpu) {
186 case APU:
187 waitq = &cx->mb_apu_waitq;
188 mb_lock = &cx->epu2apu_mb_lock;
189 break;
190 case CPU:
191 waitq = &cx->mb_cpu_waitq;
192 mb_lock = &cx->epu2cpu_mb_lock;
193 break;
194 default:
195 CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu);
196 return -EINVAL;
197 }
198
199 mutex_lock(mb_lock);
204 cx18_setup_page(cx, SCB_OFFSET); 200 cx18_setup_page(cx, SCB_OFFSET);
205 mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req); 201 mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
206 202
207 if (mb == NULL) { 203 if (mb == NULL) {
204 mutex_unlock(mb_lock);
208 CX18_ERR("mb %s busy\n", info->name); 205 CX18_ERR("mb %s busy\n", info->name);
209 return -EBUSY; 206 return -EBUSY;
210 } 207 }
@@ -216,34 +213,35 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
216 cx18_writel(cx, 0, &mb->error); 213 cx18_writel(cx, 0, &mb->error);
217 cx18_writel(cx, req, &mb->request); 214 cx18_writel(cx, req, &mb->request);
218 215
219 switch (info->rpu) {
220 case APU: waitq = &cx->mb_apu_waitq; break;
221 case CPU: waitq = &cx->mb_cpu_waitq; break;
222 case EPU: waitq = &cx->mb_epu_waitq; break;
223 case HPU: waitq = &cx->mb_hpu_waitq; break;
224 default: return -EINVAL;
225 }
226 if (info->flags & API_FAST) 216 if (info->flags & API_FAST)
227 timeout /= 2; 217 timeout /= 2;
228 cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); 218 cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq);
229 219
230 while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request) 220 sig = wait_event_interruptible_timeout(
231 && cnt < 660) { 221 *waitq,
232 if (cnt > 200 && !in_atomic()) 222 cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request),
233 sig = cx18_msleep_timeout(10, 1); 223 msecs_to_jiffies(timeout));
234 cnt++; 224 if (sig == 0) {
235 } 225 /* Timed out */
236 if (sig)
237 return -EINTR;
238 if (cnt == 660) {
239 cx18_writel(cx, oldreq, &mb->request); 226 cx18_writel(cx, oldreq, &mb->request);
240 CX18_ERR("mb %s failed\n", info->name); 227 mutex_unlock(mb_lock);
228 CX18_ERR("sending %s timed out waiting for RPU to respond\n",
229 info->name);
241 return -EINVAL; 230 return -EINVAL;
231 } else if (sig < 0) {
232 /* Interrupted */
233 cx18_writel(cx, oldreq, &mb->request);
234 mutex_unlock(mb_lock);
235 CX18_WARN("sending %s interrupted waiting for RPU to respond\n",
236 info->name);
237 return -EINTR;
242 } 238 }
239
243 for (i = 0; i < MAX_MB_ARGUMENTS; i++) 240 for (i = 0; i < MAX_MB_ARGUMENTS; i++)
244 data[i] = cx18_readl(cx, &mb->args[i]); 241 data[i] = cx18_readl(cx, &mb->args[i]);
245 err = cx18_readl(cx, &mb->error); 242 err = cx18_readl(cx, &mb->error);
246 if (!in_atomic() && (info->flags & API_SLOW)) 243 mutex_unlock(mb_lock);
244 if (info->flags & API_SLOW)
247 cx18_msleep_timeout(300, 0); 245 cx18_msleep_timeout(300, 0);
248 if (err) 246 if (err)
249 CX18_DEBUG_API("mailbox error %08x for command %s\n", err, 247 CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h
index d995641536b3..54758f32db1e 100644
--- a/drivers/media/video/cx18/cx18-mailbox.h
+++ b/drivers/media/video/cx18/cx18-mailbox.h
@@ -30,6 +30,11 @@
30#define MB_RESERVED_HANDLE_0 0 30#define MB_RESERVED_HANDLE_0 0
31#define MB_RESERVED_HANDLE_1 0xFFFFFFFF 31#define MB_RESERVED_HANDLE_1 0xFFFFFFFF
32 32
33#define APU 0
34#define CPU 1
35#define EPU 2
36#define HPU 3
37
33struct cx18; 38struct cx18;
34 39
35/* The cx18_mailbox struct is the mailbox structure which is used for passing 40/* The cx18_mailbox struct is the mailbox structure which is used for passing
@@ -68,6 +73,6 @@ int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd,
68int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...); 73int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...);
69int cx18_api_func(void *priv, u32 cmd, int in, int out, 74int cx18_api_func(void *priv, u32 cmd, int in, int out,
70 u32 data[CX2341X_MBOX_MAX_DATA]); 75 u32 data[CX2341X_MBOX_MAX_DATA]);
71long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb); 76long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb, int rpu);
72 77
73#endif 78#endif