aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/virtio/virtio_ring.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-02-04 11:00:54 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-02-04 11:00:54 -0500
commit93890b71a34f9490673a6edd56b61c2124215e46 (patch)
treec5d82620f2cb69f0bf43639e63f54b0c0e2eb744 /drivers/virtio/virtio_ring.c
parentf5bb3a5e9dcdb8435471562b6cada89525cf4df1 (diff)
parent6b35e40767c6c1ac783330109ae8e0c09ea6bc82 (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.c51
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. */
175static 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
184static inline bool more_used(const struct vring_virtqueue *vq) 174static 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
223static bool vring_restart(struct virtqueue *_vq) 213static 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
223static 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}
269EXPORT_SYMBOL_GPL(vring_interrupt);
262 270
263static struct virtqueue_ops vring_vq_ops = { 271static 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
271struct virtqueue *vring_new_virtqueue(unsigned int num, 279struct 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}
322EXPORT_SYMBOL_GPL(vring_new_virtqueue);
314 323
315void vring_del_virtqueue(struct virtqueue *vq) 324void vring_del_virtqueue(struct virtqueue *vq)
316{ 325{
317 kfree(to_vvq(vq)); 326 kfree(to_vvq(vq));
318} 327}
328EXPORT_SYMBOL_GPL(vring_del_virtqueue);
319 329
330MODULE_LICENSE("GPL");