diff options
author | Andy Walls <awalls@radix.net> | 2008-11-08 12:19:37 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 06:38:03 -0500 |
commit | 330c6ec8942765e81f237bd58020da1b161935ce (patch) | |
tree | 110bdf6daf5f280a9f3159136caa47e48e5fbaef | |
parent | ac50441720332f22a9d85ac03151d6acb7bc55d6 (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>
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.c | 2 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-driver.h | 7 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-io.c | 4 | ||||
-rw-r--r-- | drivers/media/video/cx18/cx18-mailbox.c | 47 |
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 */ |
188 | int cx18_msleep_timeout(unsigned int msecs, int intr) | 188 | int 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 | |||
365 | struct 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 */ |
364 | struct cx18 { | 370 | struct 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 | ||
121 | static 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 | ||
122 | static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) | 128 | static 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++) |