/* The pointer to our (page) of device descriptions. */
static void *lguest_devices;
-/* Unique numbering for lguest devices. */
-static unsigned int dev_index;
-
/* For Guests, device memory can be used as normal memory, so we cast away the
* __iomem to quieten sparse. */
static inline void *lguest_map(unsigned long phys_addr, unsigned long pages)
{
- return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages);
+ return (__force void *)ioremap_cache(phys_addr, PAGE_SIZE*pages);
}
static inline void lguest_unmap(void *addr)
return features;
}
-static void lg_set_features(struct virtio_device *vdev, u32 features)
+/* The virtio core takes the features the Host offers, and copies the
+ * ones supported by the driver into the vdev->features array. Once
+ * that's all sorted out, this routine is called so we can tell the
+ * Host which features we understand and accept. */
+static void lg_finalize_features(struct virtio_device *vdev)
{
- unsigned int i;
+ unsigned int i, bits;
struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
/* Second half of bitmap is features we accept. */
u8 *out_features = lg_features(desc) + desc->feature_len;
+ /* Give virtio_ring a chance to accept features. */
+ vring_transport_features(vdev);
+
+ /* The vdev->feature array is a Linux bitmask: this isn't the
+ * same as a the simple array of bits used by lguest devices
+ * for features. So we do this slow, manual conversion which is
+ * completely general. */
memset(out_features, 0, desc->feature_len);
- for (i = 0; i < min(desc->feature_len * 8, 32); i++) {
- if (features & (1 << i))
+ bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
+ for (i = 0; i < bits; i++) {
+ if (test_bit(i, vdev->features))
out_features[i / 8] |= (1 << (i % 8));
}
}
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);
}
/*
/* The ops structure which hooks everything together. */
static struct virtio_config_ops lguest_config_ops = {
.get_features = lg_get_features,
- .set_features = lg_set_features,
+ .finalize_features = lg_finalize_features,
.get = lg_get,
.set = lg_set,
.get_status = lg_get_status,
* As Andrew Tridgell says, "Untested code is buggy code".
*
* It's worth reading this carefully: we start with a pointer to the new device
- * descriptor in the "lguest_devices" page. */
-static void add_lguest_device(struct lguest_device_desc *d)
+ * descriptor in the "lguest_devices" page, and the offset into the device
+ * descriptor page so we can uniquely identify it if things go badly wrong. */
+static void add_lguest_device(struct lguest_device_desc *d,
+ unsigned int offset)
{
struct lguest_device *ldev;
* it. */
ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
if (!ldev) {
- printk(KERN_EMERG "Cannot allocate lguest dev %u\n",
- dev_index++);
+ printk(KERN_EMERG "Cannot allocate lguest dev %u type %u\n",
+ offset, d->type);
return;
}
/* This devices' parent is the lguest/ dir. */
ldev->vdev.dev.parent = &lguest_root;
/* We have a unique device index thanks to the dev_index counter. */
- ldev->vdev.index = dev_index++;
- /* The device type comes straight from the descriptor. There's also a
- * device vendor field in the virtio_device struct, which we leave as
- * 0. */
ldev->vdev.id.device = d->type;
/* We have a simple set of routines for querying the device's
* configuration information and setting its status. */
* virtio_device and calls device_register(). This makes the bus
* infrastructure look for a matching driver. */
if (register_virtio_device(&ldev->vdev) != 0) {
- printk(KERN_ERR "Failed to register lguest device %u\n",
- ldev->vdev.index);
+ printk(KERN_ERR "Failed to register lguest dev %u type %u\n",
+ offset, d->type);
kfree(ldev);
}
}
break;
printk("Device at %i has size %u\n", i, desc_size(d));
- add_lguest_device(d);
+ add_lguest_device(d, i);
}
}