aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/virtual/lguest/lguest.c25
-rw-r--r--drivers/lguest/lguest_device.c37
2 files changed, 28 insertions, 34 deletions
diff --git a/Documentation/virtual/lguest/lguest.c b/Documentation/virtual/lguest/lguest.c
index e3b9bb7a644..80261d34da3 100644
--- a/Documentation/virtual/lguest/lguest.c
+++ b/Documentation/virtual/lguest/lguest.c
@@ -1095,9 +1095,10 @@ static void update_device_status(struct device *dev)
1095 warnx("Device %s configuration FAILED", dev->name); 1095 warnx("Device %s configuration FAILED", dev->name);
1096 if (dev->running) 1096 if (dev->running)
1097 reset_device(dev); 1097 reset_device(dev);
1098 } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { 1098 } else {
1099 if (!dev->running) 1099 if (dev->running)
1100 start_device(dev); 1100 err(1, "Device %s features finalized twice", dev->name);
1101 start_device(dev);
1101 } 1102 }
1102} 1103}
1103 1104
@@ -1122,25 +1123,11 @@ static void handle_output(unsigned long addr)
1122 return; 1123 return;
1123 } 1124 }
1124 1125
1125 /* 1126 /* Devices should not be used before features are finalized. */
1126 * Devices *can* be used before status is set to DRIVER_OK.
1127 * The original plan was that they would never do this: they
1128 * would always finish setting up their status bits before
1129 * actually touching the virtqueues. In practice, we allowed
1130 * them to, and they do (eg. the disk probes for partition
1131 * tables as part of initialization).
1132 *
1133 * If we see this, we start the device: once it's running, we
1134 * expect the device to catch all the notifications.
1135 */
1136 for (vq = i->vq; vq; vq = vq->next) { 1127 for (vq = i->vq; vq; vq = vq->next) {
1137 if (addr != vq->config.pfn*getpagesize()) 1128 if (addr != vq->config.pfn*getpagesize())
1138 continue; 1129 continue;
1139 if (i->running) 1130 errx(1, "Notification on %s before setup!", i->name);
1140 errx(1, "Notification on running %s", i->name);
1141 /* This just calls create_thread() for each virtqueue */
1142 start_device(i);
1143 return;
1144 } 1131 }
1145 } 1132 }
1146 1133
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index 69c84a1d88e..5289ffa2e50 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/*