···131131 /* Any queues attached to this device */132132 struct virtqueue *vq;133133134134+ /* Handle status being finalized (ie. feature bits stable). */135135+ void (*ready)(struct device *me);136136+134137 /* Device-specific data. */135138 void *priv;136139};···928925 write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));929926}930927931931-/* When the Guest asks us to reset a device, it's is fairly easy. */932932-static void reset_device(struct device *dev)928928+/* When the Guest tells us they updated the status field, we handle it. */929929+static void update_device_status(struct device *dev)933930{934931 struct virtqueue *vq;935932936936- verbose("Resetting device %s\n", dev->name);937937- /* Clear the status. */938938- dev->desc->status = 0;933933+ /* This is a reset. */934934+ if (dev->desc->status == 0) {935935+ verbose("Resetting device %s\n", dev->name);939936940940- /* Clear any features they've acked. */941941- memset(get_feature_bits(dev) + dev->desc->feature_len, 0,942942- dev->desc->feature_len);937937+ /* Clear any features they've acked. */938938+ memset(get_feature_bits(dev) + dev->desc->feature_len, 0,939939+ dev->desc->feature_len);943940944944- /* Zero out the virtqueues. */945945- for (vq = dev->vq; vq; vq = vq->next) {946946- memset(vq->vring.desc, 0,947947- vring_size(vq->config.num, getpagesize()));948948- vq->last_avail_idx = 0;941941+ /* Zero out the virtqueues. */942942+ for (vq = dev->vq; vq; vq = vq->next) {943943+ memset(vq->vring.desc, 0,944944+ vring_size(vq->config.num, getpagesize()));945945+ vq->last_avail_idx = 0;946946+ }947947+ } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {948948+ warnx("Device %s configuration FAILED", dev->name);949949+ } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {950950+ unsigned int i;951951+952952+ verbose("Device %s OK: offered", dev->name);953953+ for (i = 0; i < dev->desc->feature_len; i++)954954+ verbose(" %08x", get_feature_bits(dev)[i]);955955+ verbose(", accepted");956956+ for (i = 0; i < dev->desc->feature_len; i++)957957+ verbose(" %08x", get_feature_bits(dev)958958+ [dev->desc->feature_len+i]);959959+960960+ if (dev->ready)961961+ dev->ready(dev);949962 }950963}951964···973954974955 /* Check each device and virtqueue. */975956 for (i = devices.dev; i; i = i->next) {976976- /* Notifications to device descriptors reset the device. */957957+ /* Notifications to device descriptors update device status. */977958 if (from_guest_phys(addr) == i->desc) {978978- reset_device(i);959959+ update_device_status(i);979960 return;980961 }981962···11891170 dev->handle_input = handle_input;11901171 dev->name = name;11911172 dev->vq = NULL;11731173+ dev->ready = NULL;1192117411931175 /* Append to device list. Prepending to a single-linked list is11941176 * easier, but the user expects the devices to be arranged on the bus
+16-10
drivers/lguest/lguest_device.c
···144144 return to_lgdev(vdev)->desc->status;145145}146146147147-static void lg_set_status(struct virtio_device *vdev, u8 status)148148-{149149- BUG_ON(!status);150150- to_lgdev(vdev)->desc->status = status;151151-}152152-153153-/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor154154- * address of the device. The Host will zero the status and all the155155- * features. */156156-static void lg_reset(struct virtio_device *vdev)147147+/* To notify on status updates, we (ab)use the NOTIFY hypercall, with the148148+ * descriptor address of the device. A zero status means "reset". */149149+static void set_status(struct virtio_device *vdev, u8 status)157150{158151 unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;159152153153+ /* We set the status. */154154+ to_lgdev(vdev)->desc->status = status;160155 hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);156156+}157157+158158+static void lg_set_status(struct virtio_device *vdev, u8 status)159159+{160160+ BUG_ON(!status);161161+ set_status(vdev, status);162162+}163163+164164+static void lg_reset(struct virtio_device *vdev)165165+{166166+ set_status(vdev, 0);161167}162168163169/*