diff options
| -rw-r--r-- | Documentation/lguest/lguest.c | 50 | ||||
| -rw-r--r-- | drivers/lguest/lguest_device.c | 20 |
2 files changed, 48 insertions, 22 deletions
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index 5cd705c3d75b..3be8ab2a886a 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c | |||
| @@ -131,6 +131,9 @@ struct device | |||
| 131 | /* Any queues attached to this device */ | 131 | /* Any queues attached to this device */ |
| 132 | struct virtqueue *vq; | 132 | struct virtqueue *vq; |
| 133 | 133 | ||
| 134 | /* Handle status being finalized (ie. feature bits stable). */ | ||
| 135 | void (*ready)(struct device *me); | ||
| 136 | |||
| 134 | /* Device-specific data. */ | 137 | /* Device-specific data. */ |
| 135 | void *priv; | 138 | void *priv; |
| 136 | }; | 139 | }; |
| @@ -925,24 +928,40 @@ static void enable_fd(int fd, struct virtqueue *vq) | |||
| 925 | write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd)); | 928 | write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd)); |
| 926 | } | 929 | } |
| 927 | 930 | ||
| 928 | /* When the Guest asks us to reset a device, it's is fairly easy. */ | 931 | /* When the Guest tells us they updated the status field, we handle it. */ |
| 929 | static void reset_device(struct device *dev) | 932 | static void update_device_status(struct device *dev) |
| 930 | { | 933 | { |
| 931 | struct virtqueue *vq; | 934 | struct virtqueue *vq; |
| 932 | 935 | ||
| 933 | verbose("Resetting device %s\n", dev->name); | 936 | /* This is a reset. */ |
| 934 | /* Clear the status. */ | 937 | if (dev->desc->status == 0) { |
| 935 | dev->desc->status = 0; | 938 | verbose("Resetting device %s\n", dev->name); |
| 936 | 939 | ||
| 937 | /* Clear any features they've acked. */ | 940 | /* Clear any features they've acked. */ |
| 938 | memset(get_feature_bits(dev) + dev->desc->feature_len, 0, | 941 | memset(get_feature_bits(dev) + dev->desc->feature_len, 0, |
| 939 | dev->desc->feature_len); | 942 | dev->desc->feature_len); |
| 940 | 943 | ||
| 941 | /* Zero out the virtqueues. */ | 944 | /* Zero out the virtqueues. */ |
| 942 | for (vq = dev->vq; vq; vq = vq->next) { | 945 | for (vq = dev->vq; vq; vq = vq->next) { |
| 943 | memset(vq->vring.desc, 0, | 946 | memset(vq->vring.desc, 0, |
| 944 | vring_size(vq->config.num, getpagesize())); | 947 | vring_size(vq->config.num, getpagesize())); |
| 945 | vq->last_avail_idx = 0; | 948 | vq->last_avail_idx = 0; |
| 949 | } | ||
| 950 | } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { | ||
| 951 | warnx("Device %s configuration FAILED", dev->name); | ||
| 952 | } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { | ||
| 953 | unsigned int i; | ||
| 954 | |||
| 955 | verbose("Device %s OK: offered", dev->name); | ||
| 956 | for (i = 0; i < dev->desc->feature_len; i++) | ||
| 957 | verbose(" %08x", get_feature_bits(dev)[i]); | ||
| 958 | verbose(", accepted"); | ||
| 959 | for (i = 0; i < dev->desc->feature_len; i++) | ||
| 960 | verbose(" %08x", get_feature_bits(dev) | ||
| 961 | [dev->desc->feature_len+i]); | ||
| 962 | |||
| 963 | if (dev->ready) | ||
| 964 | dev->ready(dev); | ||
| 946 | } | 965 | } |
| 947 | } | 966 | } |
| 948 | 967 | ||
| @@ -954,9 +973,9 @@ static void handle_output(int fd, unsigned long addr) | |||
| 954 | 973 | ||
| 955 | /* Check each device and virtqueue. */ | 974 | /* Check each device and virtqueue. */ |
| 956 | for (i = devices.dev; i; i = i->next) { | 975 | for (i = devices.dev; i; i = i->next) { |
| 957 | /* Notifications to device descriptors reset the device. */ | 976 | /* Notifications to device descriptors update device status. */ |
| 958 | if (from_guest_phys(addr) == i->desc) { | 977 | if (from_guest_phys(addr) == i->desc) { |
| 959 | reset_device(i); | 978 | update_device_status(i); |
| 960 | return; | 979 | return; |
| 961 | } | 980 | } |
| 962 | 981 | ||
| @@ -1170,6 +1189,7 @@ static struct device *new_device(const char *name, u16 type, int fd, | |||
| 1170 | dev->handle_input = handle_input; | 1189 | dev->handle_input = handle_input; |
| 1171 | dev->name = name; | 1190 | dev->name = name; |
| 1172 | dev->vq = NULL; | 1191 | dev->vq = NULL; |
| 1192 | dev->ready = NULL; | ||
| 1173 | 1193 | ||
| 1174 | /* Append to device list. Prepending to a single-linked list is | 1194 | /* Append to device list. Prepending to a single-linked list is |
| 1175 | * easier, but the user expects the devices to be arranged on the bus | 1195 | * easier, but the user expects the devices to be arranged on the bus |
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c index 7a643a6ee9a1..8080249957af 100644 --- a/drivers/lguest/lguest_device.c +++ b/drivers/lguest/lguest_device.c | |||
| @@ -144,20 +144,26 @@ static u8 lg_get_status(struct virtio_device *vdev) | |||
| 144 | return to_lgdev(vdev)->desc->status; | 144 | return to_lgdev(vdev)->desc->status; |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | /* To notify on status updates, we (ab)use the NOTIFY hypercall, with the | ||
| 148 | * descriptor address of the device. A zero status means "reset". */ | ||
| 149 | static void set_status(struct virtio_device *vdev, u8 status) | ||
| 150 | { | ||
| 151 | unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; | ||
| 152 | |||
| 153 | /* We set the status. */ | ||
| 154 | to_lgdev(vdev)->desc->status = status; | ||
| 155 | hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0); | ||
| 156 | } | ||
| 157 | |||
| 147 | static void lg_set_status(struct virtio_device *vdev, u8 status) | 158 | static void lg_set_status(struct virtio_device *vdev, u8 status) |
| 148 | { | 159 | { |
| 149 | BUG_ON(!status); | 160 | BUG_ON(!status); |
| 150 | to_lgdev(vdev)->desc->status = status; | 161 | set_status(vdev, status); |
| 151 | } | 162 | } |
| 152 | 163 | ||
| 153 | /* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor | ||
| 154 | * address of the device. The Host will zero the status and all the | ||
| 155 | * features. */ | ||
| 156 | static void lg_reset(struct virtio_device *vdev) | 164 | static void lg_reset(struct virtio_device *vdev) |
| 157 | { | 165 | { |
| 158 | unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; | 166 | set_status(vdev, 0); |
| 159 | |||
| 160 | hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0); | ||
| 161 | } | 167 | } |
| 162 | 168 | ||
| 163 | /* | 169 | /* |
