aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2008-11-08 12:19:37 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-30 06:38:03 -0500
commit330c6ec8942765e81f237bd58020da1b161935ce (patch)
tree110bdf6daf5f280a9f3159136caa47e48e5fbaef /drivers/media/video/cx18
parentac50441720332f22a9d85ac03151d6acb7bc55d6 (diff)
V4L/DVB (9596): cx18: Further changes to improve mailbox protocol integrity & performnce
All waits for cx18 mailbox API commands are now uninterruptable. Added code to collect mailbox ack statistics. Tweaked timeouts based on collected stats and video vertical frame and field rates. 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.c2
-rw-r--r--drivers/media/video/cx18/cx18-driver.h7
-rw-r--r--drivers/media/video/cx18/cx18-io.c4
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c47
4 files changed, 42 insertions, 18 deletions
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 3079e466e6e7..8ef11d578b8d 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -187,7 +187,7 @@ MODULE_VERSION(CX18_VERSION);
187/* Generic utility functions */ 187/* Generic utility functions */
188int cx18_msleep_timeout(unsigned int msecs, int intr) 188int cx18_msleep_timeout(unsigned int msecs, int intr)
189{ 189{
190 int timeout = msecs_to_jiffies(msecs); 190 long int timeout = msecs_to_jiffies(msecs);
191 int sig; 191 int sig;
192 192
193 do { 193 do {
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index e2ec15549783..ce76806759ec 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -360,6 +360,12 @@ struct cx18_mmio_stats {
360 atomic_t retried_read[CX18_MAX_MMIO_RD_RETRIES+1]; 360 atomic_t retried_read[CX18_MAX_MMIO_RD_RETRIES+1];
361}; 361};
362 362
363#define CX18_MAX_MB_ACK_DELAY 100
364
365struct cx18_mbox_stats {
366 atomic_t mb_ack_delay[CX18_MAX_MB_ACK_DELAY+1];
367};
368
363/* Struct to hold info about cx18 cards */ 369/* Struct to hold info about cx18 cards */
364struct cx18 { 370struct cx18 {
365 int num; /* board number, -1 during init! */ 371 int num; /* board number, -1 during init! */
@@ -452,6 +458,7 @@ struct cx18 {
452 458
453 /* Statistics */ 459 /* Statistics */
454 struct cx18_mmio_stats mmio_stats; 460 struct cx18_mmio_stats mmio_stats;
461 struct cx18_mbox_stats mbox_stats;
455 462
456 /* v4l2 and User settings */ 463 /* v4l2 and User settings */
457 464
diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/video/cx18/cx18-io.c
index 0ad8dea3e600..48a8adc83c2f 100644
--- a/drivers/media/video/cx18/cx18-io.c
+++ b/drivers/media/video/cx18/cx18-io.c
@@ -37,6 +37,10 @@ void cx18_log_statistics(struct cx18 *cx)
37 for (i = 0; i <= CX18_MAX_MMIO_RD_RETRIES; i++) 37 for (i = 0; i <= CX18_MAX_MMIO_RD_RETRIES; i++)
38 CX18_DEBUG_INFO("retried_read[%d] = %d\n", i, 38 CX18_DEBUG_INFO("retried_read[%d] = %d\n", i,
39 atomic_read(&cx->mmio_stats.retried_read[i])); 39 atomic_read(&cx->mmio_stats.retried_read[i]));
40 for (i = 0; i <= CX18_MAX_MB_ACK_DELAY; i++)
41 if (atomic_read(&cx->mbox_stats.mb_ack_delay[i]))
42 CX18_DEBUG_INFO("mb_ack_delay[%d] = %d\n", i,
43 atomic_read(&cx->mbox_stats.mb_ack_delay[i]));
40 return; 44 return;
41} 45}
42 46
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 0de4b9a7bbca..35f7188d4d3b 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -118,6 +118,12 @@ long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb, int rpu)
118 return 0; 118 return 0;
119} 119}
120 120
121static void cx18_api_log_ack_delay(struct cx18 *cx, int msecs)
122{
123 if (msecs > CX18_MAX_MB_ACK_DELAY)
124 msecs = CX18_MAX_MB_ACK_DELAY;
125 atomic_inc(&cx->mbox_stats.mb_ack_delay[msecs]);
126}
121 127
122static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) 128static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
123{ 129{
@@ -127,8 +133,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
127 u32 __iomem *xpu_state; 133 u32 __iomem *xpu_state;
128 wait_queue_head_t *waitq; 134 wait_queue_head_t *waitq;
129 struct mutex *mb_lock; 135 struct mutex *mb_lock;
130 int timeout = 100; 136 long int timeout, ret;
131 long unsigned int j, ret;
132 int i; 137 int i;
133 138
134 if (info == NULL) { 139 if (info == NULL) {
@@ -176,18 +181,18 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
176 */ 181 */
177 state = cx18_readl(cx, xpu_state); 182 state = cx18_readl(cx, xpu_state);
178 req = cx18_readl(cx, &mb->request); 183 req = cx18_readl(cx, &mb->request);
179 j = msecs_to_jiffies(timeout); 184 timeout = msecs_to_jiffies(20); /* 1 field at 50 Hz vertical refresh */
180 ret = wait_event_timeout(*waitq, 185 ret = wait_event_timeout(*waitq,
181 (ack = cx18_readl(cx, &mb->ack)) == req, 186 (ack = cx18_readl(cx, &mb->ack)) == req,
182 j); 187 timeout);
183 if (req != ack) { 188 if (req != ack) {
184 /* waited long enough, make the mbox "not busy" from our end */ 189 /* waited long enough, make the mbox "not busy" from our end */
185 cx18_writel(cx, req, &mb->ack); 190 cx18_writel(cx, req, &mb->ack);
186 CX18_ERR("mbox was found stuck busy when setting up for %s; " 191 CX18_ERR("mbox was found stuck busy when setting up for %s; "
187 "clearing busy and trying to proceed\n", info->name); 192 "clearing busy and trying to proceed\n", info->name);
188 } else if (ret != j) 193 } else if (ret != timeout)
189 CX18_DEBUG_API("waited %u usecs for busy mbox to be acked\n", 194 CX18_DEBUG_API("waited %u usecs for busy mbox to be acked\n",
190 jiffies_to_usecs(j-ret)); 195 jiffies_to_usecs(timeout-ret));
191 196
192 /* Build the outgoing mailbox */ 197 /* Build the outgoing mailbox */
193 req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1; 198 req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1;
@@ -199,24 +204,28 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
199 cx18_writel(cx, req, &mb->request); 204 cx18_writel(cx, req, &mb->request);
200 cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */ 205 cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */
201 206
202 /* Notify the XPU and wait for it to send an Ack back */ 207 /*
203 if (info->flags & API_FAST) 208 * Notify the XPU and wait for it to send an Ack back
204 timeout /= 2; 209 * 21 ms = ~ 0.5 frames at a frame rate of 24 fps
205 j = msecs_to_jiffies(timeout); 210 * 42 ms = ~ 1 frame at a frame rate of 24 fps
211 */
212 timeout = msecs_to_jiffies((info->flags & API_FAST) ? 21 : 42);
206 213
207 CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n", 214 CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n",
208 irq, info->name); 215 irq, info->name);
209 cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); 216 cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq);
210 217
211 ret = wait_event_interruptible_timeout( 218 ret = wait_event_timeout(
212 *waitq, 219 *waitq,
213 cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request), 220 cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request),
214 j); 221 timeout);
215 if (ret == 0) { 222 if (ret == 0) {
216 /* Timed out */ 223 /* Timed out */
217 mutex_unlock(mb_lock); 224 mutex_unlock(mb_lock);
218 CX18_ERR("sending %s timed out waiting for RPU " 225 i = jiffies_to_msecs(timeout);
219 "acknowledgement\n", info->name); 226 cx18_api_log_ack_delay(cx, i);
227 CX18_WARN("sending %s timed out waiting %d msecs for RPU "
228 "acknowledgement\n", info->name, i);
220 return -EINVAL; 229 return -EINVAL;
221 } else if (ret < 0) { 230 } else if (ret < 0) {
222 /* Interrupted */ 231 /* Interrupted */
@@ -224,9 +233,13 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
224 CX18_WARN("sending %s was interrupted waiting for RPU" 233 CX18_WARN("sending %s was interrupted waiting for RPU"
225 "acknowledgement\n", info->name); 234 "acknowledgement\n", info->name);
226 return -EINTR; 235 return -EINTR;
227 } else if (ret != j) 236 }
228 CX18_DEBUG_HI_API("waited %u usecs for %s to be acked\n", 237
229 jiffies_to_usecs(j-ret), info->name); 238 i = jiffies_to_msecs(timeout-ret);
239 cx18_api_log_ack_delay(cx, i);
240 if (ret != timeout)
241 CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n",
242 i, info->name);
230 243
231 /* Collect data returned by the XPU */ 244 /* Collect data returned by the XPU */
232 for (i = 0; i < MAX_MB_ARGUMENTS; i++) 245 for (i = 0; i < MAX_MB_ARGUMENTS; i++)