aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2011-07-22 01:09:49 -0400
committerRusty Russell <rusty@rustcorp.com.au>2011-07-22 01:09:49 -0400
commit3c3ed482dc077a67903a58c9e1aedba1bb18c18a (patch)
treead3987515d68fcfa7155574e53ab47aabd41e593 /drivers
parent6d7a5d1ea34495ecb1d608f0e40afba7776ee408 (diff)
lguest: Simplify device initialization.
We used to notify the Host every time we updated a device's status. However, it only really needs to know when we're resetting the device, or failed to initialize it, or when we've finished our feature negotiation. In particular, we used to wait for VIRTIO_CONFIG_S_DRIVER_OK in the status byte before starting the device service threads. But this corresponds to the successful finish of device initialization, which might (like virtio_blk's partition scanning) use the device. So we had a hack, if they used the device before we expected we started the threads anyway. Now we hook into the finalize_features hook in the Guest: at that point we tell the Launcher that it can rely on the features we have acked. On the Launcher side, we look at the status at that point, and start servicing the device. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/lguest/lguest_device.c37
1 files changed, 22 insertions, 15 deletions
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index 69c84a1d88ea..5289ffa2e500 100644
--- a/drivers/lguest/lguest_device.c
+++ b/drivers/lguest/lguest_device.c
@@ -109,6 +109,17 @@ static u32 lg_get_features(struct virtio_device *vdev)
109} 109}
110 110
111/* 111/*
112 * To notify on reset or feature finalization, we (ab)use the NOTIFY
113 * hypercall, with the descriptor address of the device.
114 */
115static void status_notify(struct virtio_device *vdev)
116{
117 unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
118
119 hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0);
120}
121
122/*
112 * The virtio core takes the features the Host offers, and copies the ones 123 * The virtio core takes the features the Host offers, and copies the ones
113 * supported by the driver into the vdev->features array. Once that's all 124 * supported by the driver into the vdev->features array. Once that's all
114 * sorted out, this routine is called so we can tell the Host which features we 125 * sorted out, this routine is called so we can tell the Host which features we
@@ -135,6 +146,9 @@ static void lg_finalize_features(struct virtio_device *vdev)
135 if (test_bit(i, vdev->features)) 146 if (test_bit(i, vdev->features))
136 out_features[i / 8] |= (1 << (i % 8)); 147 out_features[i / 8] |= (1 << (i % 8));
137 } 148 }
149
150 /* Tell Host we've finished with this device's feature negotiation */
151 status_notify(vdev);
138} 152}
139 153
140/* Once they've found a field, getting a copy of it is easy. */ 154/* Once they've found a field, getting a copy of it is easy. */
@@ -168,28 +182,21 @@ static u8 lg_get_status(struct virtio_device *vdev)
168 return to_lgdev(vdev)->desc->status; 182 return to_lgdev(vdev)->desc->status;
169} 183}
170 184
171/*
172 * To notify on status updates, we (ab)use the NOTIFY hypercall, with the
173 * descriptor address of the device. A zero status means "reset".
174 */
175static void set_status(struct virtio_device *vdev, u8 status)
176{
177 unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
178
179 /* We set the status. */
180 to_lgdev(vdev)->desc->status = status;
181 hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0);
182}
183
184static void lg_set_status(struct virtio_device *vdev, u8 status) 185static void lg_set_status(struct virtio_device *vdev, u8 status)
185{ 186{
186 BUG_ON(!status); 187 BUG_ON(!status);
187 set_status(vdev, status); 188 to_lgdev(vdev)->desc->status = status;
189
190 /* Tell Host immediately if we failed. */
191 if (status & VIRTIO_CONFIG_S_FAILED)
192 status_notify(vdev);
188} 193}
189 194
190static void lg_reset(struct virtio_device *vdev) 195static void lg_reset(struct virtio_device *vdev)
191{ 196{
192 set_status(vdev, 0); 197 /* 0 status means "reset" */
198 to_lgdev(vdev)->desc->status = 0;
199 status_notify(vdev);
193} 200}
194 201
195/* 202/*