aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lguest/lguest_device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/lguest/lguest_device.c')
-rw-r--r--drivers/lguest/lguest_device.c93
1 files changed, 51 insertions, 42 deletions
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index 2bc9bf7e88e5..1a8de57289eb 100644
--- a/drivers/lguest/lguest_device.c
+++ b/drivers/lguest/lguest_device.c
@@ -20,14 +20,11 @@
20/* The pointer to our (page) of device descriptions. */ 20/* The pointer to our (page) of device descriptions. */
21static void *lguest_devices; 21static void *lguest_devices;
22 22
23/* Unique numbering for lguest devices. */
24static unsigned int dev_index;
25
26/* For Guests, device memory can be used as normal memory, so we cast away the 23/* For Guests, device memory can be used as normal memory, so we cast away the
27 * __iomem to quieten sparse. */ 24 * __iomem to quieten sparse. */
28static inline void *lguest_map(unsigned long phys_addr, unsigned long pages) 25static inline void *lguest_map(unsigned long phys_addr, unsigned long pages)
29{ 26{
30 return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages); 27 return (__force void *)ioremap_cache(phys_addr, PAGE_SIZE*pages);
31} 28}
32 29
33static inline void lguest_unmap(void *addr) 30static inline void lguest_unmap(void *addr)
@@ -85,27 +82,34 @@ static unsigned desc_size(const struct lguest_device_desc *desc)
85 + desc->config_len; 82 + desc->config_len;
86} 83}
87 84
88/* This tests (and acknowleges) a feature bit. */ 85/* This gets the device's feature bits. */
89static bool lg_feature(struct virtio_device *vdev, unsigned fbit) 86static u32 lg_get_features(struct virtio_device *vdev)
90{ 87{
88 unsigned int i;
89 u32 features = 0;
91 struct lguest_device_desc *desc = to_lgdev(vdev)->desc; 90 struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
92 u8 *features; 91 u8 *in_features = lg_features(desc);
93 92
94 /* Obviously if they ask for a feature off the end of our feature 93 /* We do this the slow but generic way. */
95 * bitmap, it's not set. */ 94 for (i = 0; i < min(desc->feature_len * 8, 32); i++)
96 if (fbit / 8 > desc->feature_len) 95 if (in_features[i / 8] & (1 << (i % 8)))
97 return false; 96 features |= (1 << i);
98 97
99 /* The feature bitmap comes after the virtqueues. */ 98 return features;
100 features = lg_features(desc); 99}
101 if (!(features[fbit / 8] & (1 << (fbit % 8)))) 100
102 return false; 101static void lg_set_features(struct virtio_device *vdev, u32 features)
103 102{
104 /* We set the matching bit in the other half of the bitmap to tell the 103 unsigned int i;
105 * Host we want to use this feature. We don't use this yet, but we 104 struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
106 * could in future. */ 105 /* Second half of bitmap is features we accept. */
107 features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8)); 106 u8 *out_features = lg_features(desc) + desc->feature_len;
108 return true; 107
108 memset(out_features, 0, desc->feature_len);
109 for (i = 0; i < min(desc->feature_len * 8, 32); i++) {
110 if (features & (1 << i))
111 out_features[i / 8] |= (1 << (i % 8));
112 }
109} 113}
110 114
111/* Once they've found a field, getting a copy of it is easy. */ 115/* Once they've found a field, getting a copy of it is easy. */
@@ -137,20 +141,26 @@ static u8 lg_get_status(struct virtio_device *vdev)
137 return to_lgdev(vdev)->desc->status; 141 return to_lgdev(vdev)->desc->status;
138} 142}
139 143
144/* To notify on status updates, we (ab)use the NOTIFY hypercall, with the
145 * descriptor address of the device. A zero status means "reset". */
146static void set_status(struct virtio_device *vdev, u8 status)
147{
148 unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
149
150 /* We set the status. */
151 to_lgdev(vdev)->desc->status = status;
152 hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
153}
154
140static void lg_set_status(struct virtio_device *vdev, u8 status) 155static void lg_set_status(struct virtio_device *vdev, u8 status)
141{ 156{
142 BUG_ON(!status); 157 BUG_ON(!status);
143 to_lgdev(vdev)->desc->status = status; 158 set_status(vdev, status);
144} 159}
145 160
146/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor
147 * address of the device. The Host will zero the status and all the
148 * features. */
149static void lg_reset(struct virtio_device *vdev) 161static void lg_reset(struct virtio_device *vdev)
150{ 162{
151 unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; 163 set_status(vdev, 0);
152
153 hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
154} 164}
155 165
156/* 166/*
@@ -286,7 +296,8 @@ static void lg_del_vq(struct virtqueue *vq)
286 296
287/* The ops structure which hooks everything together. */ 297/* The ops structure which hooks everything together. */
288static struct virtio_config_ops lguest_config_ops = { 298static struct virtio_config_ops lguest_config_ops = {
289 .feature = lg_feature, 299 .get_features = lg_get_features,
300 .set_features = lg_set_features,
290 .get = lg_get, 301 .get = lg_get,
291 .set = lg_set, 302 .set = lg_set,
292 .get_status = lg_get_status, 303 .get_status = lg_get_status,
@@ -311,8 +322,10 @@ static struct device lguest_root = {
311 * As Andrew Tridgell says, "Untested code is buggy code". 322 * As Andrew Tridgell says, "Untested code is buggy code".
312 * 323 *
313 * It's worth reading this carefully: we start with a pointer to the new device 324 * It's worth reading this carefully: we start with a pointer to the new device
314 * descriptor in the "lguest_devices" page. */ 325 * descriptor in the "lguest_devices" page, and the offset into the device
315static void add_lguest_device(struct lguest_device_desc *d) 326 * descriptor page so we can uniquely identify it if things go badly wrong. */
327static void add_lguest_device(struct lguest_device_desc *d,
328 unsigned int offset)
316{ 329{
317 struct lguest_device *ldev; 330 struct lguest_device *ldev;
318 331
@@ -320,18 +333,14 @@ static void add_lguest_device(struct lguest_device_desc *d)
320 * it. */ 333 * it. */
321 ldev = kzalloc(sizeof(*ldev), GFP_KERNEL); 334 ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
322 if (!ldev) { 335 if (!ldev) {
323 printk(KERN_EMERG "Cannot allocate lguest dev %u\n", 336 printk(KERN_EMERG "Cannot allocate lguest dev %u type %u\n",
324 dev_index++); 337 offset, d->type);
325 return; 338 return;
326 } 339 }
327 340
328 /* This devices' parent is the lguest/ dir. */ 341 /* This devices' parent is the lguest/ dir. */
329 ldev->vdev.dev.parent = &lguest_root; 342 ldev->vdev.dev.parent = &lguest_root;
330 /* We have a unique device index thanks to the dev_index counter. */ 343 /* We have a unique device index thanks to the dev_index counter. */
331 ldev->vdev.index = dev_index++;
332 /* The device type comes straight from the descriptor. There's also a
333 * device vendor field in the virtio_device struct, which we leave as
334 * 0. */
335 ldev->vdev.id.device = d->type; 344 ldev->vdev.id.device = d->type;
336 /* We have a simple set of routines for querying the device's 345 /* We have a simple set of routines for querying the device's
337 * configuration information and setting its status. */ 346 * configuration information and setting its status. */
@@ -343,8 +352,8 @@ static void add_lguest_device(struct lguest_device_desc *d)
343 * virtio_device and calls device_register(). This makes the bus 352 * virtio_device and calls device_register(). This makes the bus
344 * infrastructure look for a matching driver. */ 353 * infrastructure look for a matching driver. */
345 if (register_virtio_device(&ldev->vdev) != 0) { 354 if (register_virtio_device(&ldev->vdev) != 0) {
346 printk(KERN_ERR "Failed to register lguest device %u\n", 355 printk(KERN_ERR "Failed to register lguest dev %u type %u\n",
347 ldev->vdev.index); 356 offset, d->type);
348 kfree(ldev); 357 kfree(ldev);
349 } 358 }
350} 359}
@@ -365,7 +374,7 @@ static void scan_devices(void)
365 break; 374 break;
366 375
367 printk("Device at %i has size %u\n", i, desc_size(d)); 376 printk("Device at %i has size %u\n", i, desc_size(d));
368 add_lguest_device(d); 377 add_lguest_device(d, i);
369 } 378 }
370} 379}
371 380