diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-02-04 11:00:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-02-04 11:00:54 -0500 |
commit | 93890b71a34f9490673a6edd56b61c2124215e46 (patch) | |
tree | c5d82620f2cb69f0bf43639e63f54b0c0e2eb744 /drivers/virtio/virtio_ring.c | |
parent | f5bb3a5e9dcdb8435471562b6cada89525cf4df1 (diff) | |
parent | 6b35e40767c6c1ac783330109ae8e0c09ea6bc82 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus: (25 commits)
virtio: balloon driver
virtio: Use PCI revision field to indicate virtio PCI ABI version
virtio: PCI device
virtio_blk: implement naming for vda-vdz,vdaa-vdzz,vdaaa-vdzzz
virtio_blk: Dont waste major numbers
virtio_blk: provide getgeo
virtio_net: parametrize the napi_weight for virtio receive queue.
virtio: free transmit skbs when notified, not on next xmit.
virtio: flush buffers on open
virtnet: remove double ether_setup
virtio: Allow virtio to be modular and used by modules
virtio: Use the sg_phys convenience function.
virtio: Put the virtio under the virtualization menu
virtio: handle interrupts after callbacks turned off
virtio: reset function
virtio: populate network rings in the probe routine, not open
virtio: Tweak virtio_net defines
virtio: Net header needs hdr_len
virtio: remove unused id field from struct virtio_blk_outhdr
virtio: clarify NO_NOTIFY flag usage
...
Diffstat (limited to 'drivers/virtio/virtio_ring.c')
-rw-r--r-- | drivers/virtio/virtio_ring.c | 51 |
1 files changed, 31 insertions, 20 deletions
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 1dc04b6684e6..3a28c1382131 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c | |||
@@ -87,6 +87,8 @@ static int vring_add_buf(struct virtqueue *_vq, | |||
87 | if (vq->num_free < out + in) { | 87 | if (vq->num_free < out + in) { |
88 | pr_debug("Can't add buf len %i - avail = %i\n", | 88 | pr_debug("Can't add buf len %i - avail = %i\n", |
89 | out + in, vq->num_free); | 89 | out + in, vq->num_free); |
90 | /* We notify *even if* VRING_USED_F_NO_NOTIFY is set here. */ | ||
91 | vq->notify(&vq->vq); | ||
90 | END_USE(vq); | 92 | END_USE(vq); |
91 | return -ENOSPC; | 93 | return -ENOSPC; |
92 | } | 94 | } |
@@ -97,16 +99,14 @@ static int vring_add_buf(struct virtqueue *_vq, | |||
97 | head = vq->free_head; | 99 | head = vq->free_head; |
98 | for (i = vq->free_head; out; i = vq->vring.desc[i].next, out--) { | 100 | for (i = vq->free_head; out; i = vq->vring.desc[i].next, out--) { |
99 | vq->vring.desc[i].flags = VRING_DESC_F_NEXT; | 101 | vq->vring.desc[i].flags = VRING_DESC_F_NEXT; |
100 | vq->vring.desc[i].addr = (page_to_pfn(sg_page(sg))<<PAGE_SHIFT) | 102 | vq->vring.desc[i].addr = sg_phys(sg); |
101 | + sg->offset; | ||
102 | vq->vring.desc[i].len = sg->length; | 103 | vq->vring.desc[i].len = sg->length; |
103 | prev = i; | 104 | prev = i; |
104 | sg++; | 105 | sg++; |
105 | } | 106 | } |
106 | for (; in; i = vq->vring.desc[i].next, in--) { | 107 | for (; in; i = vq->vring.desc[i].next, in--) { |
107 | vq->vring.desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE; | 108 | vq->vring.desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE; |
108 | vq->vring.desc[i].addr = (page_to_pfn(sg_page(sg))<<PAGE_SHIFT) | 109 | vq->vring.desc[i].addr = sg_phys(sg); |
109 | + sg->offset; | ||
110 | vq->vring.desc[i].len = sg->length; | 110 | vq->vring.desc[i].len = sg->length; |
111 | prev = i; | 111 | prev = i; |
112 | sg++; | 112 | sg++; |
@@ -171,16 +171,6 @@ static void detach_buf(struct vring_virtqueue *vq, unsigned int head) | |||
171 | vq->num_free++; | 171 | vq->num_free++; |
172 | } | 172 | } |
173 | 173 | ||
174 | /* FIXME: We need to tell other side about removal, to synchronize. */ | ||
175 | static void vring_shutdown(struct virtqueue *_vq) | ||
176 | { | ||
177 | struct vring_virtqueue *vq = to_vvq(_vq); | ||
178 | unsigned int i; | ||
179 | |||
180 | for (i = 0; i < vq->vring.num; i++) | ||
181 | detach_buf(vq, i); | ||
182 | } | ||
183 | |||
184 | static inline bool more_used(const struct vring_virtqueue *vq) | 174 | static inline bool more_used(const struct vring_virtqueue *vq) |
185 | { | 175 | { |
186 | return vq->last_used_idx != vq->vring.used->idx; | 176 | return vq->last_used_idx != vq->vring.used->idx; |
@@ -220,7 +210,17 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len) | |||
220 | return ret; | 210 | return ret; |
221 | } | 211 | } |
222 | 212 | ||
223 | static bool vring_restart(struct virtqueue *_vq) | 213 | static void vring_disable_cb(struct virtqueue *_vq) |
214 | { | ||
215 | struct vring_virtqueue *vq = to_vvq(_vq); | ||
216 | |||
217 | START_USE(vq); | ||
218 | BUG_ON(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT); | ||
219 | vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; | ||
220 | END_USE(vq); | ||
221 | } | ||
222 | |||
223 | static bool vring_enable_cb(struct virtqueue *_vq) | ||
224 | { | 224 | { |
225 | struct vring_virtqueue *vq = to_vvq(_vq); | 225 | struct vring_virtqueue *vq = to_vvq(_vq); |
226 | 226 | ||
@@ -253,26 +253,34 @@ irqreturn_t vring_interrupt(int irq, void *_vq) | |||
253 | if (unlikely(vq->broken)) | 253 | if (unlikely(vq->broken)) |
254 | return IRQ_HANDLED; | 254 | return IRQ_HANDLED; |
255 | 255 | ||
256 | /* Other side may have missed us turning off the interrupt, | ||
257 | * but we should preserve disable semantic for virtio users. */ | ||
258 | if (unlikely(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) { | ||
259 | pr_debug("virtqueue interrupt after disable for %p\n", vq); | ||
260 | return IRQ_HANDLED; | ||
261 | } | ||
262 | |||
256 | pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback); | 263 | pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback); |
257 | if (vq->vq.callback && !vq->vq.callback(&vq->vq)) | 264 | if (vq->vq.callback) |
258 | vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT; | 265 | vq->vq.callback(&vq->vq); |
259 | 266 | ||
260 | return IRQ_HANDLED; | 267 | return IRQ_HANDLED; |
261 | } | 268 | } |
269 | EXPORT_SYMBOL_GPL(vring_interrupt); | ||
262 | 270 | ||
263 | static struct virtqueue_ops vring_vq_ops = { | 271 | static struct virtqueue_ops vring_vq_ops = { |
264 | .add_buf = vring_add_buf, | 272 | .add_buf = vring_add_buf, |
265 | .get_buf = vring_get_buf, | 273 | .get_buf = vring_get_buf, |
266 | .kick = vring_kick, | 274 | .kick = vring_kick, |
267 | .restart = vring_restart, | 275 | .disable_cb = vring_disable_cb, |
268 | .shutdown = vring_shutdown, | 276 | .enable_cb = vring_enable_cb, |
269 | }; | 277 | }; |
270 | 278 | ||
271 | struct virtqueue *vring_new_virtqueue(unsigned int num, | 279 | struct virtqueue *vring_new_virtqueue(unsigned int num, |
272 | struct virtio_device *vdev, | 280 | struct virtio_device *vdev, |
273 | void *pages, | 281 | void *pages, |
274 | void (*notify)(struct virtqueue *), | 282 | void (*notify)(struct virtqueue *), |
275 | bool (*callback)(struct virtqueue *)) | 283 | void (*callback)(struct virtqueue *)) |
276 | { | 284 | { |
277 | struct vring_virtqueue *vq; | 285 | struct vring_virtqueue *vq; |
278 | unsigned int i; | 286 | unsigned int i; |
@@ -311,9 +319,12 @@ struct virtqueue *vring_new_virtqueue(unsigned int num, | |||
311 | 319 | ||
312 | return &vq->vq; | 320 | return &vq->vq; |
313 | } | 321 | } |
322 | EXPORT_SYMBOL_GPL(vring_new_virtqueue); | ||
314 | 323 | ||
315 | void vring_del_virtqueue(struct virtqueue *vq) | 324 | void vring_del_virtqueue(struct virtqueue *vq) |
316 | { | 325 | { |
317 | kfree(to_vvq(vq)); | 326 | kfree(to_vvq(vq)); |
318 | } | 327 | } |
328 | EXPORT_SYMBOL_GPL(vring_del_virtqueue); | ||
319 | 329 | ||
330 | MODULE_LICENSE("GPL"); | ||