diff options
Diffstat (limited to 'drivers/lguest/lguest_device.c')
-rw-r--r-- | drivers/lguest/lguest_device.c | 93 |
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. */ |
21 | static void *lguest_devices; | 21 | static void *lguest_devices; |
22 | 22 | ||
23 | /* Unique numbering for lguest devices. */ | ||
24 | static 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. */ |
28 | static inline void *lguest_map(unsigned long phys_addr, unsigned long pages) | 25 | static 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 | ||
33 | static inline void lguest_unmap(void *addr) | 30 | static 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. */ |
89 | static bool lg_feature(struct virtio_device *vdev, unsigned fbit) | 86 | static 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; | 101 | static 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". */ | ||
146 | static 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 | |||
140 | static void lg_set_status(struct virtio_device *vdev, u8 status) | 155 | static 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. */ | ||
149 | static void lg_reset(struct virtio_device *vdev) | 161 | static 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. */ |
288 | static struct virtio_config_ops lguest_config_ops = { | 298 | static 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 |
315 | static void add_lguest_device(struct lguest_device_desc *d) | 326 | * descriptor page so we can uniquely identify it if things go badly wrong. */ |
327 | static 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 | ||