Blame view

drivers/lguest/lguest_device.c 15.6 KB
2e04ef769   Rusty Russell   lguest: fix comme...
1
2
  /*P:050
   * Lguest guests use a very simple method to describe devices.  It's a
a6bd8e130   Rusty Russell   lguest: comment d...
3
   * series of device descriptors contained just above the top of normal Guest
19f1537b7   Rusty Russell   Lguest support fo...
4
5
6
7
   * memory.
   *
   * We use the standard "virtio" device infrastructure, which provides us with a
   * console, a network and a block driver.  Each one expects some configuration
2e04ef769   Rusty Russell   lguest: fix comme...
8
9
   * information and a "virtqueue" or two to send and receive data.
  :*/
19f1537b7   Rusty Russell   Lguest support fo...
10
11
12
13
14
15
16
17
  #include <linux/init.h>
  #include <linux/bootmem.h>
  #include <linux/lguest_launcher.h>
  #include <linux/virtio.h>
  #include <linux/virtio_config.h>
  #include <linux/interrupt.h>
  #include <linux/virtio_ring.h>
  #include <linux/err.h>
39a0e33da   Paul Gortmaker   lguest: add expor...
18
  #include <linux/export.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
19
  #include <linux/slab.h>
19f1537b7   Rusty Russell   Lguest support fo...
20
21
22
23
24
25
  #include <asm/io.h>
  #include <asm/paravirt.h>
  #include <asm/lguest_hcall.h>
  
  /* The pointer to our (page) of device descriptions. */
  static void *lguest_devices;
2e04ef769   Rusty Russell   lguest: fix comme...
26
27
28
29
  /*
   * For Guests, device memory can be used as normal memory, so we cast away the
   * __iomem to quieten sparse.
   */
19f1537b7   Rusty Russell   Lguest support fo...
30
31
  static inline void *lguest_map(unsigned long phys_addr, unsigned long pages)
  {
e27810f11   Rusty Russell   lguest: use iorem...
32
  	return (__force void *)ioremap_cache(phys_addr, PAGE_SIZE*pages);
19f1537b7   Rusty Russell   Lguest support fo...
33
34
35
36
37
38
  }
  
  static inline void lguest_unmap(void *addr)
  {
  	iounmap((__force void __iomem *)addr);
  }
2e04ef769   Rusty Russell   lguest: fix comme...
39
40
41
42
  /*D:100
   * Each lguest device is just a virtio device plus a pointer to its entry
   * in the lguest_devices page.
   */
19f1537b7   Rusty Russell   Lguest support fo...
43
44
45
46
47
48
  struct lguest_device {
  	struct virtio_device vdev;
  
  	/* The entry in the lguest_devices page for this device. */
  	struct lguest_device_desc *desc;
  };
2e04ef769   Rusty Russell   lguest: fix comme...
49
50
  /*
   * Since the virtio infrastructure hands us a pointer to the virtio_device all
19f1537b7   Rusty Russell   Lguest support fo...
51
   * the time, it helps to have a curt macro to get a pointer to the struct
2e04ef769   Rusty Russell   lguest: fix comme...
52
53
   * lguest_device it's enclosed in.
   */
25478445c   Alexey Dobriyan   Fix container_of(...
54
  #define to_lgdev(vd) container_of(vd, struct lguest_device, vdev)
19f1537b7   Rusty Russell   Lguest support fo...
55
56
57
58
  
  /*D:130
   * Device configurations
   *
a586d4f60   Rusty Russell   virtio: simplify ...
59
   * The configuration information for a device consists of one or more
a6bd8e130   Rusty Russell   lguest: comment d...
60
   * virtqueues, a feature bitmap, and some configuration bytes.  The
6e5aa7efb   Rusty Russell   virtio: reset fun...
61
   * configuration bytes don't really matter to us: the Launcher sets them up, and
a586d4f60   Rusty Russell   virtio: simplify ...
62
   * the driver will look at them during setup.
19f1537b7   Rusty Russell   Lguest support fo...
63
   *
a586d4f60   Rusty Russell   virtio: simplify ...
64
   * A convenient routine to return the device's virtqueue config array:
2e04ef769   Rusty Russell   lguest: fix comme...
65
66
   * immediately after the descriptor.
   */
a586d4f60   Rusty Russell   virtio: simplify ...
67
68
69
70
  static struct lguest_vqconfig *lg_vq(const struct lguest_device_desc *desc)
  {
  	return (void *)(desc + 1);
  }
19f1537b7   Rusty Russell   Lguest support fo...
71

a586d4f60   Rusty Russell   virtio: simplify ...
72
73
74
75
76
  /* The features come immediately after the virtqueues. */
  static u8 *lg_features(const struct lguest_device_desc *desc)
  {
  	return (void *)(lg_vq(desc) + desc->num_vq);
  }
19f1537b7   Rusty Russell   Lguest support fo...
77

a586d4f60   Rusty Russell   virtio: simplify ...
78
79
  /* The config space comes after the two feature bitmasks. */
  static u8 *lg_config(const struct lguest_device_desc *desc)
19f1537b7   Rusty Russell   Lguest support fo...
80
  {
a586d4f60   Rusty Russell   virtio: simplify ...
81
82
  	return lg_features(desc) + desc->feature_len * 2;
  }
19f1537b7   Rusty Russell   Lguest support fo...
83

a586d4f60   Rusty Russell   virtio: simplify ...
84
85
86
87
88
89
90
91
  /* The total size of the config page used by this device (incl. desc) */
  static unsigned desc_size(const struct lguest_device_desc *desc)
  {
  	return sizeof(*desc)
  		+ desc->num_vq * sizeof(struct lguest_vqconfig)
  		+ desc->feature_len * 2
  		+ desc->config_len;
  }
c45a6816c   Rusty Russell   virtio: explicit ...
92
93
  /* This gets the device's feature bits. */
  static u32 lg_get_features(struct virtio_device *vdev)
a586d4f60   Rusty Russell   virtio: simplify ...
94
  {
c45a6816c   Rusty Russell   virtio: explicit ...
95
96
  	unsigned int i;
  	u32 features = 0;
a586d4f60   Rusty Russell   virtio: simplify ...
97
  	struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
c45a6816c   Rusty Russell   virtio: explicit ...
98
99
100
101
102
103
104
105
106
  	u8 *in_features = lg_features(desc);
  
  	/* We do this the slow but generic way. */
  	for (i = 0; i < min(desc->feature_len * 8, 32); i++)
  		if (in_features[i / 8] & (1 << (i % 8)))
  			features |= (1 << i);
  
  	return features;
  }
2e04ef769   Rusty Russell   lguest: fix comme...
107
  /*
3c3ed482d   Rusty Russell   lguest: Simplify ...
108
109
110
111
112
113
114
115
116
117
118
   * To notify on reset or feature finalization, we (ab)use the NOTIFY
   * hypercall, with the descriptor address of the device.
   */
  static void status_notify(struct virtio_device *vdev)
  {
  	unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
  
  	hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0);
  }
  
  /*
2e04ef769   Rusty Russell   lguest: fix comme...
119
120
121
122
123
   * 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.
   */
c624896e4   Rusty Russell   virtio: Rename se...
124
  static void lg_finalize_features(struct virtio_device *vdev)
c45a6816c   Rusty Russell   virtio: explicit ...
125
  {
c624896e4   Rusty Russell   virtio: Rename se...
126
  	unsigned int i, bits;
c45a6816c   Rusty Russell   virtio: explicit ...
127
128
129
  	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;
e34f87256   Rusty Russell   virtio: Add trans...
130
131
  	/* Give virtio_ring a chance to accept features. */
  	vring_transport_features(vdev);
2e04ef769   Rusty Russell   lguest: fix comme...
132
133
134
135
136
  	/*
  	 * 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.
  	 */
c45a6816c   Rusty Russell   virtio: explicit ...
137
  	memset(out_features, 0, desc->feature_len);
c624896e4   Rusty Russell   virtio: Rename se...
138
139
140
  	bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
  	for (i = 0; i < bits; i++) {
  		if (test_bit(i, vdev->features))
c45a6816c   Rusty Russell   virtio: explicit ...
141
142
  			out_features[i / 8] |= (1 << (i % 8));
  	}
3c3ed482d   Rusty Russell   lguest: Simplify ...
143
144
145
  
  	/* Tell Host we've finished with this device's feature negotiation */
  	status_notify(vdev);
19f1537b7   Rusty Russell   Lguest support fo...
146
147
148
  }
  
  /* Once they've found a field, getting a copy of it is easy. */
a586d4f60   Rusty Russell   virtio: simplify ...
149
  static void lg_get(struct virtio_device *vdev, unsigned int offset,
19f1537b7   Rusty Russell   Lguest support fo...
150
151
  		   void *buf, unsigned len)
  {
a586d4f60   Rusty Russell   virtio: simplify ...
152
153
154
155
156
  	struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
  
  	/* Check they didn't ask for more than the length of the config! */
  	BUG_ON(offset + len > desc->config_len);
  	memcpy(buf, lg_config(desc) + offset, len);
19f1537b7   Rusty Russell   Lguest support fo...
157
158
159
  }
  
  /* Setting the contents is also trivial. */
a586d4f60   Rusty Russell   virtio: simplify ...
160
  static void lg_set(struct virtio_device *vdev, unsigned int offset,
19f1537b7   Rusty Russell   Lguest support fo...
161
162
  		   const void *buf, unsigned len)
  {
a586d4f60   Rusty Russell   virtio: simplify ...
163
164
165
166
167
  	struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
  
  	/* Check they didn't ask for more than the length of the config! */
  	BUG_ON(offset + len > desc->config_len);
  	memcpy(lg_config(desc) + offset, buf, len);
19f1537b7   Rusty Russell   Lguest support fo...
168
  }
2e04ef769   Rusty Russell   lguest: fix comme...
169
170
171
172
  /*
   * The operations to get and set the status word just access the status field
   * of the device descriptor.
   */
19f1537b7   Rusty Russell   Lguest support fo...
173
174
175
176
177
178
179
  static u8 lg_get_status(struct virtio_device *vdev)
  {
  	return to_lgdev(vdev)->desc->status;
  }
  
  static void lg_set_status(struct virtio_device *vdev, u8 status)
  {
6e5aa7efb   Rusty Russell   virtio: reset fun...
180
  	BUG_ON(!status);
3c3ed482d   Rusty Russell   lguest: Simplify ...
181
182
183
184
185
  	to_lgdev(vdev)->desc->status = status;
  
  	/* Tell Host immediately if we failed. */
  	if (status & VIRTIO_CONFIG_S_FAILED)
  		status_notify(vdev);
19f1537b7   Rusty Russell   Lguest support fo...
186
  }
6e5aa7efb   Rusty Russell   virtio: reset fun...
187
188
  static void lg_reset(struct virtio_device *vdev)
  {
3c3ed482d   Rusty Russell   lguest: Simplify ...
189
190
191
  	/* 0 status means "reset" */
  	to_lgdev(vdev)->desc->status = 0;
  	status_notify(vdev);
6e5aa7efb   Rusty Russell   virtio: reset fun...
192
  }
19f1537b7   Rusty Russell   Lguest support fo...
193
194
195
196
197
198
  /*
   * Virtqueues
   *
   * The other piece of infrastructure virtio needs is a "virtqueue": a way of
   * the Guest device registering buffers for the other side to read from or
   * write into (ie. send and receive buffers).  Each device can have multiple
e1e72965e   Rusty Russell   lguest: documenta...
199
200
   * virtqueues: for example the console driver uses one queue for sending and
   * another for receiving.
19f1537b7   Rusty Russell   Lguest support fo...
201
202
203
204
205
206
207
208
   *
   * Fortunately for us, a very fast shared-memory-plus-descriptors virtqueue
   * already exists in virtio_ring.c.  We just need to connect it up.
   *
   * We start with the information we need to keep about each virtqueue.
   */
  
  /*D:140 This is the information we remember about each virtqueue. */
1842f23c0   Rusty Russell   lguest and virtio...
209
  struct lguest_vq_info {
19f1537b7   Rusty Russell   Lguest support fo...
210
211
212
213
214
215
  	/* A copy of the information contained in the device config. */
  	struct lguest_vqconfig config;
  
  	/* The address where we mapped the virtio ring, so we can unmap it. */
  	void *pages;
  };
2e04ef769   Rusty Russell   lguest: fix comme...
216
217
  /*
   * When the virtio_ring code wants to prod the Host, it calls us here and we
a6bd8e130   Rusty Russell   lguest: comment d...
218
   * make a hypercall.  We hand the physical address of the virtqueue so the Host
2e04ef769   Rusty Russell   lguest: fix comme...
219
220
   * knows which virtqueue we're talking about.
   */
19f1537b7   Rusty Russell   Lguest support fo...
221
222
  static void lg_notify(struct virtqueue *vq)
  {
2e04ef769   Rusty Russell   lguest: fix comme...
223
224
225
226
  	/*
  	 * We store our virtqueue information in the "priv" pointer of the
  	 * virtqueue structure.
  	 */
19f1537b7   Rusty Russell   Lguest support fo...
227
  	struct lguest_vq_info *lvq = vq->priv;
091ebf07a   Rusty Russell   lguest: stop usin...
228
  	hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0, 0);
19f1537b7   Rusty Russell   Lguest support fo...
229
  }
6db6a5f3a   Rusty Russell   lguest: fix for C...
230
  /* An extern declaration inside a C file is bad form.  Don't do it. */
b6c96c021   Stratos Psomadakis   lguest: Make sure...
231
  extern int lguest_setup_irq(unsigned int irq);
6db6a5f3a   Rusty Russell   lguest: fix for C...
232

2e04ef769   Rusty Russell   lguest: fix comme...
233
  /*
a91d74a3c   Rusty Russell   lguest: update co...
234
   * This routine finds the Nth virtqueue described in the configuration of
19f1537b7   Rusty Russell   Lguest support fo...
235
236
237
238
   * this device and sets it up.
   *
   * This is kind of an ugly duckling.  It'd be nicer to have a standard
   * representation of a virtqueue in the configuration space, but it seems that
e1e72965e   Rusty Russell   lguest: documenta...
239
   * everyone wants to do it differently.  The KVM coders want the Guest to
19f1537b7   Rusty Russell   Lguest support fo...
240
241
   * allocate its own pages and tell the Host where they are, but for lguest it's
   * simpler for the Host to simply tell us where the pages are.
2e04ef769   Rusty Russell   lguest: fix comme...
242
   */
19f1537b7   Rusty Russell   Lguest support fo...
243
  static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
a586d4f60   Rusty Russell   virtio: simplify ...
244
  				    unsigned index,
9499f5e7e   Rusty Russell   virtio: add names...
245
246
  				    void (*callback)(struct virtqueue *vq),
  				    const char *name)
19f1537b7   Rusty Russell   Lguest support fo...
247
  {
a586d4f60   Rusty Russell   virtio: simplify ...
248
  	struct lguest_device *ldev = to_lgdev(vdev);
19f1537b7   Rusty Russell   Lguest support fo...
249
250
  	struct lguest_vq_info *lvq;
  	struct virtqueue *vq;
19f1537b7   Rusty Russell   Lguest support fo...
251
  	int err;
a586d4f60   Rusty Russell   virtio: simplify ...
252
253
  	/* We must have this many virtqueues. */
  	if (index >= ldev->desc->num_vq)
19f1537b7   Rusty Russell   Lguest support fo...
254
255
256
257
258
  		return ERR_PTR(-ENOENT);
  
  	lvq = kmalloc(sizeof(*lvq), GFP_KERNEL);
  	if (!lvq)
  		return ERR_PTR(-ENOMEM);
2e04ef769   Rusty Russell   lguest: fix comme...
259
260
  	/*
  	 * Make a copy of the "struct lguest_vqconfig" entry, which sits after
a586d4f60   Rusty Russell   virtio: simplify ...
261
  	 * the descriptor.  We need a copy because the config space might not
2e04ef769   Rusty Russell   lguest: fix comme...
262
263
  	 * be aligned correctly.
  	 */
a586d4f60   Rusty Russell   virtio: simplify ...
264
  	memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config));
19f1537b7   Rusty Russell   Lguest support fo...
265

a586d4f60   Rusty Russell   virtio: simplify ...
266
267
268
  	printk("Mapping virtqueue %i addr %lx
  ", index,
  	       (unsigned long)lvq->config.pfn << PAGE_SHIFT);
19f1537b7   Rusty Russell   Lguest support fo...
269
270
  	/* Figure out how many pages the ring will take, and map that memory */
  	lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
42b36cc0c   Rusty Russell   virtio: Force use...
271
  				DIV_ROUND_UP(vring_size(lvq->config.num,
2966af73e   Rusty Russell   virtio: use LGUES...
272
  							LGUEST_VRING_ALIGN),
19f1537b7   Rusty Russell   Lguest support fo...
273
274
275
276
277
  					     PAGE_SIZE));
  	if (!lvq->pages) {
  		err = -ENOMEM;
  		goto free_lvq;
  	}
2e04ef769   Rusty Russell   lguest: fix comme...
278
279
  	/*
  	 * OK, tell virtio_ring.c to set up a virtqueue now we know its size
7b21e34fd   Rusty Russell   virtio: harsher b...
280
281
282
  	 * and we've got a pointer to its pages.  Note that we set weak_barriers
  	 * to 'true': the host just a(nother) SMP CPU, so we only need inter-cpu
  	 * barriers.
2e04ef769   Rusty Russell   lguest: fix comme...
283
  	 */
7b21e34fd   Rusty Russell   virtio: harsher b...
284
285
  	vq = vring_new_virtqueue(lvq->config.num, LGUEST_VRING_ALIGN, vdev,
  				 true, lvq->pages, lg_notify, callback, name);
19f1537b7   Rusty Russell   Lguest support fo...
286
287
288
289
  	if (!vq) {
  		err = -ENOMEM;
  		goto unmap;
  	}
6db6a5f3a   Rusty Russell   lguest: fix for C...
290
  	/* Make sure the interrupt is allocated. */
b6c96c021   Stratos Psomadakis   lguest: Make sure...
291
292
293
  	err = lguest_setup_irq(lvq->config.irq);
  	if (err)
  		goto destroy_vring;
6db6a5f3a   Rusty Russell   lguest: fix for C...
294

2e04ef769   Rusty Russell   lguest: fix comme...
295
296
297
298
299
  	/*
  	 * Tell the interrupt for this virtqueue to go to the virtio_ring
  	 * interrupt handler.
  	 *
  	 * FIXME: We used to have a flag for the Host to tell us we could use
19f1537b7   Rusty Russell   Lguest support fo...
300
  	 * the interrupt as a source of randomness: it'd be nice to have that
2e04ef769   Rusty Russell   lguest: fix comme...
301
302
  	 * back.
  	 */
19f1537b7   Rusty Russell   Lguest support fo...
303
  	err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED,
bda53cd51   Mark McLoughlin   lguest: struct de...
304
  			  dev_name(&vdev->dev), vq);
19f1537b7   Rusty Russell   Lguest support fo...
305
  	if (err)
b6c96c021   Stratos Psomadakis   lguest: Make sure...
306
  		goto free_desc;
19f1537b7   Rusty Russell   Lguest support fo...
307

2e04ef769   Rusty Russell   lguest: fix comme...
308
309
310
311
  	/*
  	 * Last of all we hook up our 'struct lguest_vq_info" to the
  	 * virtqueue's priv pointer.
  	 */
19f1537b7   Rusty Russell   Lguest support fo...
312
313
  	vq->priv = lvq;
  	return vq;
b6c96c021   Stratos Psomadakis   lguest: Make sure...
314
315
  free_desc:
  	irq_free_desc(lvq->config.irq);
19f1537b7   Rusty Russell   Lguest support fo...
316
317
318
319
320
321
322
323
324
325
326
327
328
329
  destroy_vring:
  	vring_del_virtqueue(vq);
  unmap:
  	lguest_unmap(lvq->pages);
  free_lvq:
  	kfree(lvq);
  	return ERR_PTR(err);
  }
  /*:*/
  
  /* Cleaning up a virtqueue is easy */
  static void lg_del_vq(struct virtqueue *vq)
  {
  	struct lguest_vq_info *lvq = vq->priv;
74b2553f1   Rusty Russell   virtio: fix modul...
330
331
  	/* Release the interrupt */
  	free_irq(lvq->config.irq, vq);
19f1537b7   Rusty Russell   Lguest support fo...
332
333
334
335
336
337
338
  	/* Tell virtio_ring.c to free the virtqueue. */
  	vring_del_virtqueue(vq);
  	/* Unmap the pages containing the ring. */
  	lguest_unmap(lvq->pages);
  	/* Free our own queue information. */
  	kfree(lvq);
  }
d2a7ddda9   Michael S. Tsirkin   virtio: find_vqs/...
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
  static void lg_del_vqs(struct virtio_device *vdev)
  {
  	struct virtqueue *vq, *n;
  
  	list_for_each_entry_safe(vq, n, &vdev->vqs, list)
  		lg_del_vq(vq);
  }
  
  static int lg_find_vqs(struct virtio_device *vdev, unsigned nvqs,
  		       struct virtqueue *vqs[],
  		       vq_callback_t *callbacks[],
  		       const char *names[])
  {
  	struct lguest_device *ldev = to_lgdev(vdev);
  	int i;
  
  	/* We must have this many virtqueues. */
  	if (nvqs > ldev->desc->num_vq)
  		return -ENOENT;
  
  	for (i = 0; i < nvqs; ++i) {
  		vqs[i] = lg_find_vq(vdev, i, callbacks[i], names[i]);
  		if (IS_ERR(vqs[i]))
  			goto error;
  	}
  	return 0;
  
  error:
  	lg_del_vqs(vdev);
  	return PTR_ERR(vqs[i]);
  }
66846048f   Rick Jones   enable virtio_net...
370
371
372
373
  static const char *lg_bus_name(struct virtio_device *vdev)
  {
  	return "";
  }
19f1537b7   Rusty Russell   Lguest support fo...
374
375
  /* The ops structure which hooks everything together. */
  static struct virtio_config_ops lguest_config_ops = {
c45a6816c   Rusty Russell   virtio: explicit ...
376
  	.get_features = lg_get_features,
c624896e4   Rusty Russell   virtio: Rename se...
377
  	.finalize_features = lg_finalize_features,
19f1537b7   Rusty Russell   Lguest support fo...
378
379
380
381
  	.get = lg_get,
  	.set = lg_set,
  	.get_status = lg_get_status,
  	.set_status = lg_set_status,
6e5aa7efb   Rusty Russell   virtio: reset fun...
382
  	.reset = lg_reset,
d2a7ddda9   Michael S. Tsirkin   virtio: find_vqs/...
383
384
  	.find_vqs = lg_find_vqs,
  	.del_vqs = lg_del_vqs,
66846048f   Rick Jones   enable virtio_net...
385
  	.bus_name = lg_bus_name,
19f1537b7   Rusty Russell   Lguest support fo...
386
  };
2e04ef769   Rusty Russell   lguest: fix comme...
387
388
389
390
  /*
   * The root device for the lguest virtio devices.  This makes them appear as
   * /sys/devices/lguest/0,1,2 not /sys/devices/0,1,2.
   */
ff8561c4a   Mark McLoughlin   lguest: do not st...
391
  static struct device *lguest_root;
19f1537b7   Rusty Russell   Lguest support fo...
392

2e04ef769   Rusty Russell   lguest: fix comme...
393
394
  /*D:120
   * This is the core of the lguest bus: actually adding a new device.
19f1537b7   Rusty Russell   Lguest support fo...
395
396
397
398
399
400
401
   * It's a separate function because it's neater that way, and because an
   * earlier version of the code supported hotplug and unplug.  They were removed
   * early on because they were never used.
   *
   * As Andrew Tridgell says, "Untested code is buggy code".
   *
   * It's worth reading this carefully: we start with a pointer to the new device
b769f5790   Rusty Russell   virtio: set devic...
402
   * descriptor in the "lguest_devices" page, and the offset into the device
2e04ef769   Rusty Russell   lguest: fix comme...
403
404
   * descriptor page so we can uniquely identify it if things go badly wrong.
   */
b769f5790   Rusty Russell   virtio: set devic...
405
406
  static void add_lguest_device(struct lguest_device_desc *d,
  			      unsigned int offset)
19f1537b7   Rusty Russell   Lguest support fo...
407
408
  {
  	struct lguest_device *ldev;
2e04ef769   Rusty Russell   lguest: fix comme...
409
  	/* Start with zeroed memory; Linux's device layer counts on it. */
19f1537b7   Rusty Russell   Lguest support fo...
410
411
  	ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
  	if (!ldev) {
b769f5790   Rusty Russell   virtio: set devic...
412
413
414
  		printk(KERN_EMERG "Cannot allocate lguest dev %u type %u
  ",
  		       offset, d->type);
19f1537b7   Rusty Russell   Lguest support fo...
415
416
417
418
  		return;
  	}
  
  	/* This devices' parent is the lguest/ dir. */
ff8561c4a   Mark McLoughlin   lguest: do not st...
419
  	ldev->vdev.dev.parent = lguest_root;
a91d74a3c   Rusty Russell   lguest: update co...
420
421
422
423
424
  	/*
  	 * 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.
  	 */
19f1537b7   Rusty Russell   Lguest support fo...
425
  	ldev->vdev.id.device = d->type;
2e04ef769   Rusty Russell   lguest: fix comme...
426
427
428
429
  	/*
  	 * We have a simple set of routines for querying the device's
  	 * configuration information and setting its status.
  	 */
19f1537b7   Rusty Russell   Lguest support fo...
430
431
432
  	ldev->vdev.config = &lguest_config_ops;
  	/* And we remember the device's descriptor for lguest_config_ops. */
  	ldev->desc = d;
2e04ef769   Rusty Russell   lguest: fix comme...
433
434
  	/*
  	 * register_virtio_device() sets up the generic fields for the struct
19f1537b7   Rusty Russell   Lguest support fo...
435
  	 * virtio_device and calls device_register().  This makes the bus
2e04ef769   Rusty Russell   lguest: fix comme...
436
437
  	 * infrastructure look for a matching driver.
  	 */
19f1537b7   Rusty Russell   Lguest support fo...
438
  	if (register_virtio_device(&ldev->vdev) != 0) {
b769f5790   Rusty Russell   virtio: set devic...
439
440
441
  		printk(KERN_ERR "Failed to register lguest dev %u type %u
  ",
  		       offset, d->type);
19f1537b7   Rusty Russell   Lguest support fo...
442
443
444
  		kfree(ldev);
  	}
  }
2e04ef769   Rusty Russell   lguest: fix comme...
445
446
447
448
  /*D:110
   * scan_devices() simply iterates through the device page.  The type 0 is
   * reserved to mean "end of devices".
   */
19f1537b7   Rusty Russell   Lguest support fo...
449
450
451
452
453
454
  static void scan_devices(void)
  {
  	unsigned int i;
  	struct lguest_device_desc *d;
  
  	/* We start at the page beginning, and skip over each entry. */
a586d4f60   Rusty Russell   virtio: simplify ...
455
  	for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
19f1537b7   Rusty Russell   Lguest support fo...
456
457
458
459
460
  		d = lguest_devices + i;
  
  		/* Once we hit a zero, stop. */
  		if (d->type == 0)
  			break;
a586d4f60   Rusty Russell   virtio: simplify ...
461
462
  		printk("Device at %i has size %u
  ", i, desc_size(d));
b769f5790   Rusty Russell   virtio: set devic...
463
  		add_lguest_device(d, i);
19f1537b7   Rusty Russell   Lguest support fo...
464
465
  	}
  }
2e04ef769   Rusty Russell   lguest: fix comme...
466
467
  /*D:105
   * Fairly early in boot, lguest_devices_init() is called to set up the
19f1537b7   Rusty Russell   Lguest support fo...
468
469
470
471
472
473
474
475
476
477
   * lguest device infrastructure.  We check that we are a Guest by checking
   * pv_info.name: there are other ways of checking, but this seems most
   * obvious to me.
   *
   * So we can access the "struct lguest_device_desc"s easily, we map that memory
   * and store the pointer in the global "lguest_devices".  Then we register a
   * root device from which all our devices will hang (this seems to be the
   * correct sysfs incantation).
   *
   * Finally we call scan_devices() which adds all the devices found in the
2e04ef769   Rusty Russell   lguest: fix comme...
478
479
   * lguest_devices page.
   */
19f1537b7   Rusty Russell   Lguest support fo...
480
481
482
483
  static int __init lguest_devices_init(void)
  {
  	if (strcmp(pv_info.name, "lguest") != 0)
  		return 0;
ff8561c4a   Mark McLoughlin   lguest: do not st...
484
485
  	lguest_root = root_device_register("lguest");
  	if (IS_ERR(lguest_root))
19f1537b7   Rusty Russell   Lguest support fo...
486
487
488
489
490
491
492
493
494
495
  		panic("Could not register lguest root");
  
  	/* Devices are in a single page above top of "normal" mem */
  	lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
  
  	scan_devices();
  	return 0;
  }
  /* We do this after core stuff, but before the drivers. */
  postcore_initcall(lguest_devices_init);
2e04ef769   Rusty Russell   lguest: fix comme...
496
497
  /*D:150
   * At this point in the journey we used to now wade through the lguest
19f1537b7   Rusty Russell   Lguest support fo...
498
499
500
501
502
503
   * devices themselves: net, block and console.  Since they're all now virtio
   * devices rather than lguest-specific, I've decided to ignore them.  Mostly,
   * they're kind of boring.  But this does mean you'll never experience the
   * thrill of reading the forbidden love scene buried deep in the block driver.
   *
   * "make Launcher" beckons, where we answer questions like "Where do Guests
2e04ef769   Rusty Russell   lguest: fix comme...
504
505
   * come from?", and "What do you do when someone asks for optimization?".
   */