Skip to content

Commit

Permalink
lguest: make Launcher see device status updates
Browse files Browse the repository at this point in the history
This brings us closer to Real Life, where we'd examine the device
features once it's set the DRIVER_OK status bit.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
  • Loading branch information
Rusty Russell committed May 2, 2008
1 parent 9f3f746 commit a007a75
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 22 deletions.
50 changes: 35 additions & 15 deletions Documentation/lguest/lguest.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ struct device
/* Any queues attached to this device */
struct virtqueue *vq;

/* Handle status being finalized (ie. feature bits stable). */
void (*ready)(struct device *me);

/* Device-specific data. */
void *priv;
};
Expand Down Expand Up @@ -925,24 +928,40 @@ static void enable_fd(int fd, struct virtqueue *vq)
write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
}

/* When the Guest asks us to reset a device, it's is fairly easy. */
static void reset_device(struct device *dev)
/* When the Guest tells us they updated the status field, we handle it. */
static void update_device_status(struct device *dev)
{
struct virtqueue *vq;

verbose("Resetting device %s\n", dev->name);
/* Clear the status. */
dev->desc->status = 0;
/* This is a reset. */
if (dev->desc->status == 0) {
verbose("Resetting device %s\n", dev->name);

/* Clear any features they've acked. */
memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
dev->desc->feature_len);
/* Clear any features they've acked. */
memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
dev->desc->feature_len);

/* Zero out the virtqueues. */
for (vq = dev->vq; vq; vq = vq->next) {
memset(vq->vring.desc, 0,
vring_size(vq->config.num, getpagesize()));
vq->last_avail_idx = 0;
/* Zero out the virtqueues. */
for (vq = dev->vq; vq; vq = vq->next) {
memset(vq->vring.desc, 0,
vring_size(vq->config.num, getpagesize()));
vq->last_avail_idx = 0;
}
} else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
warnx("Device %s configuration FAILED", dev->name);
} else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
unsigned int i;

verbose("Device %s OK: offered", dev->name);
for (i = 0; i < dev->desc->feature_len; i++)
verbose(" %08x", get_feature_bits(dev)[i]);
verbose(", accepted");
for (i = 0; i < dev->desc->feature_len; i++)
verbose(" %08x", get_feature_bits(dev)
[dev->desc->feature_len+i]);

if (dev->ready)
dev->ready(dev);
}
}

Expand All @@ -954,9 +973,9 @@ static void handle_output(int fd, unsigned long addr)

/* Check each device and virtqueue. */
for (i = devices.dev; i; i = i->next) {
/* Notifications to device descriptors reset the device. */
/* Notifications to device descriptors update device status. */
if (from_guest_phys(addr) == i->desc) {
reset_device(i);
update_device_status(i);
return;
}

Expand Down Expand Up @@ -1170,6 +1189,7 @@ static struct device *new_device(const char *name, u16 type, int fd,
dev->handle_input = handle_input;
dev->name = name;
dev->vq = NULL;
dev->ready = NULL;

/* Append to device list. Prepending to a single-linked list is
* easier, but the user expects the devices to be arranged on the bus
Expand Down
20 changes: 13 additions & 7 deletions drivers/lguest/lguest_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,20 +144,26 @@ static u8 lg_get_status(struct virtio_device *vdev)
return to_lgdev(vdev)->desc->status;
}

/* To notify on status updates, we (ab)use the NOTIFY hypercall, with the
* descriptor address of the device. A zero status means "reset". */
static void set_status(struct virtio_device *vdev, u8 status)
{
unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;

/* We set the status. */
to_lgdev(vdev)->desc->status = status;
hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
}

static void lg_set_status(struct virtio_device *vdev, u8 status)
{
BUG_ON(!status);
to_lgdev(vdev)->desc->status = status;
set_status(vdev, status);
}

/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor
* address of the device. The Host will zero the status and all the
* features. */
static void lg_reset(struct virtio_device *vdev)
{
unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;

hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
set_status(vdev, 0);
}

/*
Expand Down

0 comments on commit a007a75

Please sign in to comment.