Blame view

drivers/virtio/virtio.c 6.54 KB
ec3d41c4d   Rusty Russell   Virtio interface
1
2
3
  #include <linux/virtio.h>
  #include <linux/spinlock.h>
  #include <linux/virtio_config.h>
b5a2c4f19   Paul Gortmaker   virtio: Add modul...
4
  #include <linux/module.h>
ec3d41c4d   Rusty Russell   Virtio interface
5

b769f5790   Rusty Russell   virtio: set devic...
6
7
  /* Unique numbering for virtio devices. */
  static unsigned int dev_index;
ec3d41c4d   Rusty Russell   Virtio interface
8
9
10
11
  static ssize_t device_show(struct device *_d,
  			   struct device_attribute *attr, char *buf)
  {
  	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
be6528b2e   Stephen Hemminger   virtio: fix forma...
12
13
  	return sprintf(buf, "0x%04x
  ", dev->id.device);
ec3d41c4d   Rusty Russell   Virtio interface
14
15
16
17
18
  }
  static ssize_t vendor_show(struct device *_d,
  			   struct device_attribute *attr, char *buf)
  {
  	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
be6528b2e   Stephen Hemminger   virtio: fix forma...
19
20
  	return sprintf(buf, "0x%04x
  ", dev->id.vendor);
ec3d41c4d   Rusty Russell   Virtio interface
21
22
23
24
25
  }
  static ssize_t status_show(struct device *_d,
  			   struct device_attribute *attr, char *buf)
  {
  	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
be6528b2e   Stephen Hemminger   virtio: fix forma...
26
27
  	return sprintf(buf, "0x%08x
  ", dev->config->get_status(dev));
ec3d41c4d   Rusty Russell   Virtio interface
28
  }
b01d9f286   Rusty Russell   Module autoprobin...
29
30
31
32
33
34
35
36
37
  static ssize_t modalias_show(struct device *_d,
  			     struct device_attribute *attr, char *buf)
  {
  	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
  
  	return sprintf(buf, "virtio:d%08Xv%08X
  ",
  		       dev->id.device, dev->id.vendor);
  }
a92892825   Rusty Russell   virtio: expose fe...
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  static ssize_t features_show(struct device *_d,
  			     struct device_attribute *attr, char *buf)
  {
  	struct virtio_device *dev = container_of(_d, struct virtio_device, dev);
  	unsigned int i;
  	ssize_t len = 0;
  
  	/* We actually represent this as a bitstring, as it could be
  	 * arbitrary length in future. */
  	for (i = 0; i < ARRAY_SIZE(dev->features)*BITS_PER_LONG; i++)
  		len += sprintf(buf+len, "%c",
  			       test_bit(i, dev->features) ? '1' : '0');
  	len += sprintf(buf+len, "
  ");
  	return len;
  }
ec3d41c4d   Rusty Russell   Virtio interface
54
55
56
57
  static struct device_attribute virtio_dev_attrs[] = {
  	__ATTR_RO(device),
  	__ATTR_RO(vendor),
  	__ATTR_RO(status),
b01d9f286   Rusty Russell   Module autoprobin...
58
  	__ATTR_RO(modalias),
a92892825   Rusty Russell   virtio: expose fe...
59
  	__ATTR_RO(features),
ec3d41c4d   Rusty Russell   Virtio interface
60
61
62
63
64
65
  	__ATTR_NULL
  };
  
  static inline int virtio_id_match(const struct virtio_device *dev,
  				  const struct virtio_device_id *id)
  {
e33538537   Christian Borntraeger   virtio: enhance i...
66
  	if (id->device != dev->id.device && id->device != VIRTIO_DEV_ANY_ID)
ec3d41c4d   Rusty Russell   Virtio interface
67
  		return 0;
c89e80168   Christian Borntraeger   virtio: fix id_ma...
68
  	return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor == dev->id.vendor;
ec3d41c4d   Rusty Russell   Virtio interface
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  }
  
  /* This looks through all the IDs a driver claims to support.  If any of them
   * match, we return 1 and the kernel will call virtio_dev_probe(). */
  static int virtio_dev_match(struct device *_dv, struct device_driver *_dr)
  {
  	unsigned int i;
  	struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
  	const struct virtio_device_id *ids;
  
  	ids = container_of(_dr, struct virtio_driver, driver)->id_table;
  	for (i = 0; ids[i].device; i++)
  		if (virtio_id_match(dev, &ids[i]))
  			return 1;
  	return 0;
  }
b01d9f286   Rusty Russell   Module autoprobin...
85
86
87
88
89
90
91
  static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env)
  {
  	struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
  
  	return add_uevent_var(env, "MODALIAS=virtio:d%08Xv%08X",
  			      dev->id.device, dev->id.vendor);
  }
ec3d41c4d   Rusty Russell   Virtio interface
92
93
94
95
  static void add_status(struct virtio_device *dev, unsigned status)
  {
  	dev->config->set_status(dev, dev->config->get_status(dev) | status);
  }
c45a6816c   Rusty Russell   virtio: explicit ...
96
97
98
99
100
101
102
103
104
105
106
107
108
  void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
  					 unsigned int fbit)
  {
  	unsigned int i;
  	struct virtio_driver *drv = container_of(vdev->dev.driver,
  						 struct virtio_driver, driver);
  
  	for (i = 0; i < drv->feature_table_size; i++)
  		if (drv->feature_table[i] == fbit)
  			return;
  	BUG();
  }
  EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature);
ec3d41c4d   Rusty Russell   Virtio interface
109
110
  static int virtio_dev_probe(struct device *_d)
  {
c45a6816c   Rusty Russell   virtio: explicit ...
111
  	int err, i;
ec3d41c4d   Rusty Russell   Virtio interface
112
113
114
  	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
  	struct virtio_driver *drv = container_of(dev->dev.driver,
  						 struct virtio_driver, driver);
c45a6816c   Rusty Russell   virtio: explicit ...
115
  	u32 device_features;
ec3d41c4d   Rusty Russell   Virtio interface
116

c45a6816c   Rusty Russell   virtio: explicit ...
117
  	/* We have a driver! */
ec3d41c4d   Rusty Russell   Virtio interface
118
  	add_status(dev, VIRTIO_CONFIG_S_DRIVER);
c45a6816c   Rusty Russell   virtio: explicit ...
119
120
121
122
123
124
125
126
127
128
129
130
  
  	/* Figure out what features the device supports. */
  	device_features = dev->config->get_features(dev);
  
  	/* Features supported by both device and driver into dev->features. */
  	memset(dev->features, 0, sizeof(dev->features));
  	for (i = 0; i < drv->feature_table_size; i++) {
  		unsigned int f = drv->feature_table[i];
  		BUG_ON(f >= 32);
  		if (device_features & (1 << f))
  			set_bit(f, dev->features);
  	}
c624896e4   Rusty Russell   virtio: Rename se...
131
  	/* Transport features always preserved to pass to finalize_features. */
dd7c7bc46   Rusty Russell   virtio: Formally ...
132
133
134
  	for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++)
  		if (device_features & (1 << i))
  			set_bit(i, dev->features);
ef688e151   Rusty Russell   virtio: meet virt...
135
  	dev->config->finalize_features(dev);
ec3d41c4d   Rusty Russell   Virtio interface
136
137
138
  	err = drv->probe(dev);
  	if (err)
  		add_status(dev, VIRTIO_CONFIG_S_FAILED);
ef688e151   Rusty Russell   virtio: meet virt...
139
  	else
b92dea67c   Mark McLoughlin   virtio: Complete ...
140
  		add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
ef688e151   Rusty Russell   virtio: meet virt...
141

ec3d41c4d   Rusty Russell   Virtio interface
142
143
  	return err;
  }
74b2553f1   Rusty Russell   virtio: fix modul...
144
145
146
147
148
  static int virtio_dev_remove(struct device *_d)
  {
  	struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
  	struct virtio_driver *drv = container_of(dev->dev.driver,
  						 struct virtio_driver, driver);
74b2553f1   Rusty Russell   virtio: fix modul...
149
  	drv->remove(dev);
6e5aa7efb   Rusty Russell   virtio: reset fun...
150
151
152
153
154
155
  
  	/* Driver should have reset device. */
  	BUG_ON(dev->config->get_status(dev));
  
  	/* Acknowledge the device's existence again. */
  	add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
74b2553f1   Rusty Russell   virtio: fix modul...
156
157
  	return 0;
  }
e962fa660   Mark McLoughlin   virtio: Use bus_t...
158
159
160
161
162
163
164
165
  static struct bus_type virtio_bus = {
  	.name  = "virtio",
  	.match = virtio_dev_match,
  	.dev_attrs = virtio_dev_attrs,
  	.uevent = virtio_uevent,
  	.probe = virtio_dev_probe,
  	.remove = virtio_dev_remove,
  };
ec3d41c4d   Rusty Russell   Virtio interface
166
167
  int register_virtio_driver(struct virtio_driver *driver)
  {
c45a6816c   Rusty Russell   virtio: explicit ...
168
169
  	/* Catch this early. */
  	BUG_ON(driver->feature_table_size && !driver->feature_table);
ec3d41c4d   Rusty Russell   Virtio interface
170
  	driver->driver.bus = &virtio_bus;
ec3d41c4d   Rusty Russell   Virtio interface
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
  	return driver_register(&driver->driver);
  }
  EXPORT_SYMBOL_GPL(register_virtio_driver);
  
  void unregister_virtio_driver(struct virtio_driver *driver)
  {
  	driver_unregister(&driver->driver);
  }
  EXPORT_SYMBOL_GPL(unregister_virtio_driver);
  
  int register_virtio_device(struct virtio_device *dev)
  {
  	int err;
  
  	dev->dev.bus = &virtio_bus;
b769f5790   Rusty Russell   virtio: set devic...
186
187
188
  
  	/* Assign a unique device index and hence name. */
  	dev->index = dev_index++;
99e0b6c8e   Kay Sievers   virtio: struct de...
189
  	dev_set_name(&dev->dev, "virtio%u", dev->index);
ec3d41c4d   Rusty Russell   Virtio interface
190

6e5aa7efb   Rusty Russell   virtio: reset fun...
191
192
193
  	/* We always start by resetting the device, in case a previous
  	 * driver messed it up.  This also tests that code path a little. */
  	dev->config->reset(dev);
ec3d41c4d   Rusty Russell   Virtio interface
194
195
  	/* Acknowledge that we've seen the device. */
  	add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
9499f5e7e   Rusty Russell   virtio: add names...
196
  	INIT_LIST_HEAD(&dev->vqs);
ec3d41c4d   Rusty Russell   Virtio interface
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  	/* device_register() causes the bus infrastructure to look for a
  	 * matching driver. */
  	err = device_register(&dev->dev);
  	if (err)
  		add_status(dev, VIRTIO_CONFIG_S_FAILED);
  	return err;
  }
  EXPORT_SYMBOL_GPL(register_virtio_device);
  
  void unregister_virtio_device(struct virtio_device *dev)
  {
  	device_unregister(&dev->dev);
  }
  EXPORT_SYMBOL_GPL(unregister_virtio_device);
ec3d41c4d   Rusty Russell   Virtio interface
211
212
213
214
215
216
  static int virtio_init(void)
  {
  	if (bus_register(&virtio_bus) != 0)
  		panic("virtio bus registration failed");
  	return 0;
  }
c6fd47011   Rusty Russell   virtio: Allow vir...
217
218
219
220
221
  
  static void __exit virtio_exit(void)
  {
  	bus_unregister(&virtio_bus);
  }
ec3d41c4d   Rusty Russell   Virtio interface
222
  core_initcall(virtio_init);
c6fd47011   Rusty Russell   virtio: Allow vir...
223
224
225
  module_exit(virtio_exit);
  
  MODULE_LICENSE("GPL");