Blame view

drivers/vdpa/vdpa.c 4.07 KB
961e9c840   Jason Wang   vDPA: introduce v...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  // SPDX-License-Identifier: GPL-2.0-only
  /*
   * vDPA bus.
   *
   * Copyright (c) 2020, Red Hat. All rights reserved.
   *     Author: Jason Wang <jasowang@redhat.com>
   *
   */
  
  #include <linux/module.h>
  #include <linux/idr.h>
  #include <linux/slab.h>
  #include <linux/vdpa.h>
  
  static DEFINE_IDA(vdpa_index_ida);
  
  static int vdpa_dev_probe(struct device *d)
  {
  	struct vdpa_device *vdev = dev_to_vdpa(d);
  	struct vdpa_driver *drv = drv_to_vdpa(vdev->dev.driver);
  	int ret = 0;
  
  	if (drv && drv->probe)
  		ret = drv->probe(vdev);
  
  	return ret;
  }
  
  static int vdpa_dev_remove(struct device *d)
  {
  	struct vdpa_device *vdev = dev_to_vdpa(d);
  	struct vdpa_driver *drv = drv_to_vdpa(vdev->dev.driver);
  
  	if (drv && drv->remove)
  		drv->remove(vdev);
  
  	return 0;
  }
  
  static struct bus_type vdpa_bus = {
  	.name  = "vdpa",
  	.probe = vdpa_dev_probe,
  	.remove = vdpa_dev_remove,
  };
  
  static void vdpa_release_dev(struct device *d)
  {
  	struct vdpa_device *vdev = dev_to_vdpa(d);
  	const struct vdpa_config_ops *ops = vdev->config;
  
  	if (ops->free)
  		ops->free(vdev);
  
  	ida_simple_remove(&vdpa_index_ida, vdev->index);
  	kfree(vdev);
  }
  
  /**
   * __vdpa_alloc_device - allocate and initilaize a vDPA device
   * This allows driver to some prepartion after device is
   * initialized but before registered.
   * @parent: the parent device
   * @config: the bus operations that is supported by this device
a9974489b   Max Gurtovoy   vdpa: remove hard...
64
   * @nvqs: number of virtqueues supported by this device
961e9c840   Jason Wang   vDPA: introduce v...
65
66
   * @size: size of the parent structure that contains private data
   *
24eae8ebf   Jason Wang   vdpa: fix typos i...
67
   * Driver should use vdpa_alloc_device() wrapper macro instead of
961e9c840   Jason Wang   vDPA: introduce v...
68
69
70
71
72
73
74
   * using this directly.
   *
   * Returns an error when parent/config/dma_dev is not set or fail to get
   * ida.
   */
  struct vdpa_device *__vdpa_alloc_device(struct device *parent,
  					const struct vdpa_config_ops *config,
a9974489b   Max Gurtovoy   vdpa: remove hard...
75
  					int nvqs,
961e9c840   Jason Wang   vDPA: introduce v...
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  					size_t size)
  {
  	struct vdpa_device *vdev;
  	int err = -EINVAL;
  
  	if (!config)
  		goto err;
  
  	if (!!config->dma_map != !!config->dma_unmap)
  		goto err;
  
  	err = -ENOMEM;
  	vdev = kzalloc(size, GFP_KERNEL);
  	if (!vdev)
  		goto err;
  
  	err = ida_simple_get(&vdpa_index_ida, 0, 0, GFP_KERNEL);
  	if (err < 0)
  		goto err_ida;
  
  	vdev->dev.bus = &vdpa_bus;
  	vdev->dev.parent = parent;
  	vdev->dev.release = vdpa_release_dev;
  	vdev->index = err;
  	vdev->config = config;
452639a64   Michael S. Tsirkin   vdpa: make sure s...
101
  	vdev->features_valid = false;
a9974489b   Max Gurtovoy   vdpa: remove hard...
102
  	vdev->nvqs = nvqs;
961e9c840   Jason Wang   vDPA: introduce v...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  
  	err = dev_set_name(&vdev->dev, "vdpa%u", vdev->index);
  	if (err)
  		goto err_name;
  
  	device_initialize(&vdev->dev);
  
  	return vdev;
  
  err_name:
  	ida_simple_remove(&vdpa_index_ida, vdev->index);
  err_ida:
  	kfree(vdev);
  err:
  	return ERR_PTR(err);
  }
  EXPORT_SYMBOL_GPL(__vdpa_alloc_device);
  
  /**
   * vdpa_register_device - register a vDPA device
ac8b85f9e   Jason Wang   vdpa: fix comment...
123
   * Callers must have a succeed call of vdpa_alloc_device() before.
961e9c840   Jason Wang   vDPA: introduce v...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
   * @vdev: the vdpa device to be registered to vDPA bus
   *
   * Returns an error when fail to add to vDPA bus
   */
  int vdpa_register_device(struct vdpa_device *vdev)
  {
  	return device_add(&vdev->dev);
  }
  EXPORT_SYMBOL_GPL(vdpa_register_device);
  
  /**
   * vdpa_unregister_device - unregister a vDPA device
   * @vdev: the vdpa device to be unregisted from vDPA bus
   */
  void vdpa_unregister_device(struct vdpa_device *vdev)
  {
  	device_unregister(&vdev->dev);
  }
  EXPORT_SYMBOL_GPL(vdpa_unregister_device);
  
  /**
   * __vdpa_register_driver - register a vDPA device driver
   * @drv: the vdpa device driver to be registered
   * @owner: module owner of the driver
   *
   * Returns an err when fail to do the registration
   */
  int __vdpa_register_driver(struct vdpa_driver *drv, struct module *owner)
  {
  	drv->driver.bus = &vdpa_bus;
  	drv->driver.owner = owner;
  
  	return driver_register(&drv->driver);
  }
  EXPORT_SYMBOL_GPL(__vdpa_register_driver);
  
  /**
   * vdpa_unregister_driver - unregister a vDPA device driver
   * @drv: the vdpa device driver to be unregistered
   */
  void vdpa_unregister_driver(struct vdpa_driver *drv)
  {
  	driver_unregister(&drv->driver);
  }
  EXPORT_SYMBOL_GPL(vdpa_unregister_driver);
  
  static int vdpa_init(void)
  {
  	return bus_register(&vdpa_bus);
  }
  
  static void __exit vdpa_exit(void)
  {
  	bus_unregister(&vdpa_bus);
  	ida_destroy(&vdpa_index_ida);
  }
  core_initcall(vdpa_init);
  module_exit(vdpa_exit);
  
  MODULE_AUTHOR("Jason Wang <jasowang@redhat.com>");
  MODULE_LICENSE("GPL v2");