aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/lguest
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2008-02-04 23:49:56 -0500
committerRusty Russell <rusty@rustcorp.com.au>2008-02-04 07:49:57 -0500
commita586d4f6016f7139d8c26df0e6927131168d3b5b (patch)
tree1c47e1a6b6b8fb18baa42f32980f29c4ae9cbbdc /drivers/lguest
parentf35d9d8aae08940b7fdd1bb8110619da2ece6b28 (diff)
virtio: simplify config mechanism.
Previously we used a type/len pair within the config space, but this seems overkill. We now simply define a structure which represents the layout in the config space: the config space can now only be extended at the end. The main driver-visible changes: 1) We indicate what fields are present with an explicit feature bit. 2) Virtqueues are explicitly numbered, and not in the config space. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/lguest')
-rw-r--r--drivers/lguest/lguest_device.c132
1 files changed, 74 insertions, 58 deletions
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index e2eec38c83c2..07f57a53658b 100644
--- a/drivers/lguest/lguest_device.c
+++ b/drivers/lguest/lguest_device.c
@@ -52,57 +52,82 @@ struct lguest_device {
52/*D:130 52/*D:130
53 * Device configurations 53 * Device configurations
54 * 54 *
55 * The configuration information for a device consists of a series of fields. 55 * The configuration information for a device consists of one or more
56 * We don't really care what they are: the Launcher set them up, and the driver 56 * virtqueues, a feature bitmaks, and some configuration bytes. The
57 * will look at them during setup. 57 * configuration bytes don't really matter to us: the Launcher set them up, and
58 * the driver will look at them during setup.
58 * 59 *
59 * For us these fields come immediately after that device's descriptor in the 60 * A convenient routine to return the device's virtqueue config array:
60 * lguest_devices page. 61 * immediately after the descriptor. */
61 * 62static struct lguest_vqconfig *lg_vq(const struct lguest_device_desc *desc)
62 * Each field starts with a "type" byte, a "length" byte, then that number of 63{
63 * bytes of configuration information. The device descriptor tells us the 64 return (void *)(desc + 1);
64 * total configuration length so we know when we've reached the last field. */ 65}
65 66
66/* type + length bytes */ 67/* The features come immediately after the virtqueues. */
67#define FHDR_LEN 2 68static u8 *lg_features(const struct lguest_device_desc *desc)
69{
70 return (void *)(lg_vq(desc) + desc->num_vq);
71}
68 72
69/* This finds the first field of a given type for a device's configuration. */ 73/* The config space comes after the two feature bitmasks. */
70static void *lg_find(struct virtio_device *vdev, u8 type, unsigned int *len) 74static u8 *lg_config(const struct lguest_device_desc *desc)
71{ 75{
72 struct lguest_device_desc *desc = to_lgdev(vdev)->desc; 76 return lg_features(desc) + desc->feature_len * 2;
73 int i; 77}
74
75 for (i = 0; i < desc->config_len; i += FHDR_LEN + desc->config[i+1]) {
76 if (desc->config[i] == type) {
77 /* Mark it used, so Host can know we looked at it, and
78 * also so we won't find the same one twice. */
79 desc->config[i] |= 0x80;
80 /* Remember, the second byte is the length. */
81 *len = desc->config[i+1];
82 /* We return a pointer to the field header. */
83 return desc->config + i;
84 }
85 }
86 78
87 /* Not found: return NULL for failure. */ 79/* The total size of the config page used by this device (incl. desc) */
88 return NULL; 80static unsigned desc_size(const struct lguest_device_desc *desc)
81{
82 return sizeof(*desc)
83 + desc->num_vq * sizeof(struct lguest_vqconfig)
84 + desc->feature_len * 2
85 + desc->config_len;
86}
87
88/* This tests (and acknowleges) a feature bit. */
89static bool lg_feature(struct virtio_device *vdev, unsigned fbit)
90{
91 struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
92 u8 *features;
93
94 /* Obviously if they ask for a feature off the end of our feature
95 * bitmap, it's not set. */
96 if (fbit / 8 > desc->feature_len)
97 return false;
98
99 /* The feature bitmap comes after the virtqueues. */
100 features = lg_features(desc);
101 if (!(features[fbit / 8] & (1 << (fbit % 8))))
102 return false;
103
104 /* We set the matching bit in the other half of the bitmap to tell the
105 * Host we want to use this feature. We don't use this yet, but we
106 * could in future. */
107 features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8));
108 return true;
89} 109}
90 110
91/* Once they've found a field, getting a copy of it is easy. */ 111/* Once they've found a field, getting a copy of it is easy. */
92static void lg_get(struct virtio_device *vdev, void *token, 112static void lg_get(struct virtio_device *vdev, unsigned int offset,
93 void *buf, unsigned len) 113 void *buf, unsigned len)
94{ 114{
95 /* Check they didn't ask for more than the length of the field! */ 115 struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
96 BUG_ON(len > ((u8 *)token)[1]); 116
97 memcpy(buf, token + FHDR_LEN, len); 117 /* Check they didn't ask for more than the length of the config! */
118 BUG_ON(offset + len > desc->config_len);
119 memcpy(buf, lg_config(desc) + offset, len);
98} 120}
99 121
100/* Setting the contents is also trivial. */ 122/* Setting the contents is also trivial. */
101static void lg_set(struct virtio_device *vdev, void *token, 123static void lg_set(struct virtio_device *vdev, unsigned int offset,
102 const void *buf, unsigned len) 124 const void *buf, unsigned len)
103{ 125{
104 BUG_ON(len > ((u8 *)token)[1]); 126 struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
105 memcpy(token + FHDR_LEN, buf, len); 127
128 /* Check they didn't ask for more than the length of the config! */
129 BUG_ON(offset + len > desc->config_len);
130 memcpy(lg_config(desc) + offset, buf, len);
106} 131}
107 132
108/* The operations to get and set the status word just access the status field 133/* The operations to get and set the status word just access the status field
@@ -165,39 +190,29 @@ static void lg_notify(struct virtqueue *vq)
165 * 190 *
166 * So we provide devices with a "find virtqueue and set it up" function. */ 191 * So we provide devices with a "find virtqueue and set it up" function. */
167static struct virtqueue *lg_find_vq(struct virtio_device *vdev, 192static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
193 unsigned index,
168 bool (*callback)(struct virtqueue *vq)) 194 bool (*callback)(struct virtqueue *vq))
169{ 195{
196 struct lguest_device *ldev = to_lgdev(vdev);
170 struct lguest_vq_info *lvq; 197 struct lguest_vq_info *lvq;
171 struct virtqueue *vq; 198 struct virtqueue *vq;
172 unsigned int len;
173 void *token;
174 int err; 199 int err;
175 200
176 /* Look for a field of the correct type to mark a virtqueue. Note that 201 /* We must have this many virtqueues. */
177 * if this succeeds, then the type will be changed so it won't be found 202 if (index >= ldev->desc->num_vq)
178 * again, and future lg_find_vq() calls will find the next
179 * virtqueue (if any). */
180 token = vdev->config->find(vdev, VIRTIO_CONFIG_F_VIRTQUEUE, &len);
181 if (!token)
182 return ERR_PTR(-ENOENT); 203 return ERR_PTR(-ENOENT);
183 204
184 lvq = kmalloc(sizeof(*lvq), GFP_KERNEL); 205 lvq = kmalloc(sizeof(*lvq), GFP_KERNEL);
185 if (!lvq) 206 if (!lvq)
186 return ERR_PTR(-ENOMEM); 207 return ERR_PTR(-ENOMEM);
187 208
188 /* Note: we could use a configuration space inside here, just like we 209 /* Make a copy of the "struct lguest_vqconfig" entry, which sits after
189 * do for the device. This would allow expansion in future, because 210 * the descriptor. We need a copy because the config space might not
190 * our configuration system is designed to be expansible. But this is 211 * be aligned correctly. */
191 * way easier. */ 212 memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config));
192 if (len != sizeof(lvq->config)) {
193 dev_err(&vdev->dev, "Unexpected virtio config len %u\n", len);
194 err = -EIO;
195 goto free_lvq;
196 }
197 /* Make a copy of the "struct lguest_vqconfig" field. We need a copy
198 * because the config space might not be aligned correctly. */
199 vdev->config->get(vdev, token, &lvq->config, sizeof(lvq->config));
200 213
214 printk("Mapping virtqueue %i addr %lx\n", index,
215 (unsigned long)lvq->config.pfn << PAGE_SHIFT);
201 /* Figure out how many pages the ring will take, and map that memory */ 216 /* Figure out how many pages the ring will take, and map that memory */
202 lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT, 217 lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
203 DIV_ROUND_UP(vring_size(lvq->config.num, 218 DIV_ROUND_UP(vring_size(lvq->config.num,
@@ -259,7 +274,7 @@ static void lg_del_vq(struct virtqueue *vq)
259 274
260/* The ops structure which hooks everything together. */ 275/* The ops structure which hooks everything together. */
261static struct virtio_config_ops lguest_config_ops = { 276static struct virtio_config_ops lguest_config_ops = {
262 .find = lg_find, 277 .feature = lg_feature,
263 .get = lg_get, 278 .get = lg_get,
264 .set = lg_set, 279 .set = lg_set,
265 .get_status = lg_get_status, 280 .get_status = lg_get_status,
@@ -329,13 +344,14 @@ static void scan_devices(void)
329 struct lguest_device_desc *d; 344 struct lguest_device_desc *d;
330 345
331 /* We start at the page beginning, and skip over each entry. */ 346 /* We start at the page beginning, and skip over each entry. */
332 for (i = 0; i < PAGE_SIZE; i += sizeof(*d) + d->config_len) { 347 for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
333 d = lguest_devices + i; 348 d = lguest_devices + i;
334 349
335 /* Once we hit a zero, stop. */ 350 /* Once we hit a zero, stop. */
336 if (d->type == 0) 351 if (d->type == 0)
337 break; 352 break;
338 353
354 printk("Device at %i has size %u\n", i, desc_size(d));
339 add_lguest_device(d); 355 add_lguest_device(d);
340 } 356 }
341} 357}