virtio: enhance id_matching for virtio drivers
[linux-2.6.git] / drivers / virtio / virtio_balloon.c
index c8a4332..26b2782 100644 (file)
@@ -56,6 +56,15 @@ static struct virtio_device_id id_table[] = {
        { 0 },
 };
 
+static u32 page_to_balloon_pfn(struct page *page)
+{
+       unsigned long pfn = page_to_pfn(page);
+
+       BUILD_BUG_ON(PAGE_SHIFT < VIRTIO_BALLOON_PFN_SHIFT);
+       /* Convert pfn from Linux page size to balloon page size. */
+       return pfn >> (PAGE_SHIFT - VIRTIO_BALLOON_PFN_SHIFT);
+}
+
 static void balloon_ack(struct virtqueue *vq)
 {
        struct virtio_balloon *vb;
@@ -99,7 +108,7 @@ static void fill_balloon(struct virtio_balloon *vb, size_t num)
                        msleep(200);
                        break;
                }
-               vb->pfns[vb->num_pfns] = page_to_pfn(page);
+               vb->pfns[vb->num_pfns] = page_to_balloon_pfn(page);
                totalram_pages--;
                vb->num_pages++;
                list_add(&page->lru, &vb->pages);
@@ -132,7 +141,7 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
        for (vb->num_pfns = 0; vb->num_pfns < num; vb->num_pfns++) {
                page = list_first_entry(&vb->pages, struct page, lru);
                list_del(&page->lru);
-               vb->pfns[vb->num_pfns] = page_to_pfn(page);
+               vb->pfns[vb->num_pfns] = page_to_balloon_pfn(page);
                vb->num_pages--;
        }
 
@@ -152,13 +161,13 @@ static void virtballoon_changed(struct virtio_device *vdev)
        wake_up(&vb->config_change);
 }
 
-static inline int towards_target(struct virtio_balloon *vb)
+static inline s64 towards_target(struct virtio_balloon *vb)
 {
        u32 v;
-       __virtio_config_val(vb->vdev,
-                           offsetof(struct virtio_balloon_config, num_pages),
-                           &v);
-       return v - vb->num_pages;
+       vb->vdev->config->get(vb->vdev,
+                             offsetof(struct virtio_balloon_config, num_pages),
+                             &v, sizeof(v));
+       return (s64)v - vb->num_pages;
 }
 
 static void update_balloon_size(struct virtio_balloon *vb)
@@ -176,12 +185,13 @@ static int balloon(void *_vballoon)
 
        set_freezable();
        while (!kthread_should_stop()) {
-               int diff;
+               s64 diff;
 
                try_to_freeze();
                wait_event_interruptible(vb->config_change,
                                         (diff = towards_target(vb)) != 0
-                                        || kthread_should_stop());
+                                        || kthread_should_stop()
+                                        || freezing(current));
                if (diff > 0)
                        fill_balloon(vb, diff);
                else if (diff < 0)
@@ -194,6 +204,9 @@ static int balloon(void *_vballoon)
 static int virtballoon_probe(struct virtio_device *vdev)
 {
        struct virtio_balloon *vb;
+       struct virtqueue *vqs[2];
+       vq_callback_t *callbacks[] = { balloon_ack, balloon_ack };
+       const char *names[] = { "inflate", "deflate" };
        int err;
 
        vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
@@ -208,33 +221,26 @@ static int virtballoon_probe(struct virtio_device *vdev)
        vb->vdev = vdev;
 
        /* We expect two virtqueues. */
-       vb->inflate_vq = vdev->config->find_vq(vdev, 0, balloon_ack);
-       if (IS_ERR(vb->inflate_vq)) {
-               err = PTR_ERR(vb->inflate_vq);
+       err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names);
+       if (err)
                goto out_free_vb;
-       }
 
-       vb->deflate_vq = vdev->config->find_vq(vdev, 1, balloon_ack);
-       if (IS_ERR(vb->deflate_vq)) {
-               err = PTR_ERR(vb->deflate_vq);
-               goto out_del_inflate_vq;
-       }
+       vb->inflate_vq = vqs[0];
+       vb->deflate_vq = vqs[1];
 
        vb->thread = kthread_run(balloon, vb, "vballoon");
        if (IS_ERR(vb->thread)) {
                err = PTR_ERR(vb->thread);
-               goto out_del_deflate_vq;
+               goto out_del_vqs;
        }
 
        vb->tell_host_first
-               = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
+               = virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
 
        return 0;
 
-out_del_deflate_vq:
-       vdev->config->del_vq(vb->deflate_vq);
-out_del_inflate_vq:
-       vdev->config->del_vq(vb->inflate_vq);
+out_del_vqs:
+       vdev->config->del_vqs(vdev);
 out_free_vb:
        kfree(vb);
 out:
@@ -254,12 +260,15 @@ static void virtballoon_remove(struct virtio_device *vdev)
        /* Now we reset the device so we can clean up the queues. */
        vdev->config->reset(vdev);
 
-       vdev->config->del_vq(vb->deflate_vq);
-       vdev->config->del_vq(vb->inflate_vq);
+       vdev->config->del_vqs(vdev);
        kfree(vb);
 }
 
+static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST };
+
 static struct virtio_driver virtio_balloon = {
+       .feature_table = features,
+       .feature_table_size = ARRAY_SIZE(features),
        .driver.name =  KBUILD_MODNAME,
        .driver.owner = THIS_MODULE,
        .id_table =     id_table,