aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2012-01-12 00:14:43 -0500
committerRusty Russell <rusty@rustcorp.com.au>2012-01-12 00:14:43 -0500
commite93300b1afc7cd4fe1e741ceaf06714d060e88b8 (patch)
tree060bb46e8d7b570fa08df94aef1cf4cc3620f8c5
parentee7cd8981e15bcb365fc762afe3fc47b8242f630 (diff)
virtio: add debugging if driver doesn't kick.
Under the existing #ifdef DEBUG, check that they don't have more than 1/10 of a second between an add_buf() and a virtqueue_notify()/virtqueue_kick_prepare() call. We could get false positives on a really busy system, but good for development. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--drivers/virtio/virtio_ring.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 36bb6a61372..79e1b292c03 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -22,6 +22,7 @@
22#include <linux/device.h> 22#include <linux/device.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/module.h> 24#include <linux/module.h>
25#include <linux/hrtimer.h>
25 26
26/* virtio guest is communicating with a virtual "device" that actually runs on 27/* virtio guest is communicating with a virtual "device" that actually runs on
27 * a host processor. Memory barriers are used to control SMP effects. */ 28 * a host processor. Memory barriers are used to control SMP effects. */
@@ -108,6 +109,10 @@ struct vring_virtqueue
108#ifdef DEBUG 109#ifdef DEBUG
109 /* They're supposed to lock for us. */ 110 /* They're supposed to lock for us. */
110 unsigned int in_use; 111 unsigned int in_use;
112
113 /* Figure out if their kicks are too delayed. */
114 bool last_add_time_valid;
115 ktime_t last_add_time;
111#endif 116#endif
112 117
113 /* Tokens for callbacks. */ 118 /* Tokens for callbacks. */
@@ -198,6 +203,19 @@ int virtqueue_add_buf(struct virtqueue *_vq,
198 203
199 BUG_ON(data == NULL); 204 BUG_ON(data == NULL);
200 205
206#ifdef DEBUG
207 {
208 ktime_t now = ktime_get();
209
210 /* No kick or get, with .1 second between? Warn. */
211 if (vq->last_add_time_valid)
212 WARN_ON(ktime_to_ms(ktime_sub(now, vq->last_add_time))
213 > 100);
214 vq->last_add_time = now;
215 vq->last_add_time_valid = true;
216 }
217#endif
218
201 /* If the host supports indirect descriptor tables, and we have multiple 219 /* If the host supports indirect descriptor tables, and we have multiple
202 * buffers, then go indirect. FIXME: tune this threshold */ 220 * buffers, then go indirect. FIXME: tune this threshold */
203 if (vq->indirect && (out + in) > 1 && vq->num_free) { 221 if (vq->indirect && (out + in) > 1 && vq->num_free) {
@@ -298,6 +316,14 @@ bool virtqueue_kick_prepare(struct virtqueue *_vq)
298 new = vq->vring.avail->idx; 316 new = vq->vring.avail->idx;
299 vq->num_added = 0; 317 vq->num_added = 0;
300 318
319#ifdef DEBUG
320 if (vq->last_add_time_valid) {
321 WARN_ON(ktime_to_ms(ktime_sub(ktime_get(),
322 vq->last_add_time)) > 100);
323 }
324 vq->last_add_time_valid = false;
325#endif
326
301 if (vq->event) { 327 if (vq->event) {
302 needs_kick = vring_need_event(vring_avail_event(&vq->vring), 328 needs_kick = vring_need_event(vring_avail_event(&vq->vring),
303 new, old); 329 new, old);
@@ -435,6 +461,10 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
435 virtio_mb(vq); 461 virtio_mb(vq);
436 } 462 }
437 463
464#ifdef DEBUG
465 vq->last_add_time_valid = false;
466#endif
467
438 END_USE(vq); 468 END_USE(vq);
439 return ret; 469 return ret;
440} 470}
@@ -620,6 +650,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
620 list_add_tail(&vq->vq.list, &vdev->vqs); 650 list_add_tail(&vq->vq.list, &vdev->vqs);
621#ifdef DEBUG 651#ifdef DEBUG
622 vq->in_use = false; 652 vq->in_use = false;
653 vq->last_add_time_valid = false;
623#endif 654#endif
624 655
625 vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC); 656 vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC);