blob: 2addb1ebc5e2f30fea82dfff0979bde6c17fe016 [file] [log] [blame]
Bin Meng640aae02018-10-15 02:21:25 -07001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
4 *
5 * VirtIO Sandbox transport driver, for testing purpose only
6 */
7
8#include <common.h>
9#include <dm.h>
10#include <virtio_types.h>
11#include <virtio.h>
12#include <virtio_ring.h>
13#include <linux/compat.h>
14#include <linux/io.h>
15
16struct virtio_sandbox_priv {
17 u8 id;
18 u8 status;
19 u64 device_features;
20 u64 driver_features;
21 ulong queue_desc;
22 ulong queue_available;
23 ulong queue_used;
24};
25
26static int virtio_sandbox_get_config(struct udevice *udev, unsigned int offset,
27 void *buf, unsigned int len)
28{
29 return 0;
30}
31
32static int virtio_sandbox_set_config(struct udevice *udev, unsigned int offset,
33 const void *buf, unsigned int len)
34{
35 return 0;
36}
37
38static int virtio_sandbox_get_status(struct udevice *udev, u8 *status)
39{
40 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
41
42 *status = priv->status;
43
44 return 0;
45}
46
47static int virtio_sandbox_set_status(struct udevice *udev, u8 status)
48{
49 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
50
51 /* We should never be setting status to 0 */
52 WARN_ON(status == 0);
53
54 priv->status = status;
55
56 return 0;
57}
58
59static int virtio_sandbox_reset(struct udevice *udev)
60{
61 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
62
63 /* 0 status means a reset */
64 priv->status = 0;
65
66 return 0;
67}
68
69static int virtio_sandbox_get_features(struct udevice *udev, u64 *features)
70{
71 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
72
73 *features = priv->device_features;
74
75 return 0;
76}
77
78static int virtio_sandbox_set_features(struct udevice *udev)
79{
80 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
81 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
82
83 priv->driver_features = uc_priv->features;
84
85 return 0;
86}
87
88static struct virtqueue *virtio_sandbox_setup_vq(struct udevice *udev,
89 unsigned int index)
90{
91 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
92 struct virtqueue *vq;
93 ulong addr;
94 int err;
95
96 /* Create the vring */
97 vq = vring_create_virtqueue(index, 4, 4096, udev);
98 if (!vq) {
99 err = -ENOMEM;
100 goto error_new_virtqueue;
101 }
102
103 addr = virtqueue_get_desc_addr(vq);
104 priv->queue_desc = addr;
105
106 addr = virtqueue_get_avail_addr(vq);
107 priv->queue_available = addr;
108
109 addr = virtqueue_get_used_addr(vq);
110 priv->queue_used = addr;
111
112 return vq;
113
114error_new_virtqueue:
115 return ERR_PTR(err);
116}
117
118static void virtio_sandbox_del_vq(struct virtqueue *vq)
119{
120 vring_del_virtqueue(vq);
121}
122
123static int virtio_sandbox_del_vqs(struct udevice *udev)
124{
125 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
126 struct virtqueue *vq, *n;
127
128 list_for_each_entry_safe(vq, n, &uc_priv->vqs, list)
129 virtio_sandbox_del_vq(vq);
130
131 return 0;
132}
133
134static int virtio_sandbox_find_vqs(struct udevice *udev, unsigned int nvqs,
135 struct virtqueue *vqs[])
136{
137 int i;
138
139 for (i = 0; i < nvqs; ++i) {
140 vqs[i] = virtio_sandbox_setup_vq(udev, i);
141 if (IS_ERR(vqs[i])) {
142 virtio_sandbox_del_vqs(udev);
143 return PTR_ERR(vqs[i]);
144 }
145 }
146
147 return 0;
148}
149
150static int virtio_sandbox_notify(struct udevice *udev, struct virtqueue *vq)
151{
152 return 0;
153}
154
155static int virtio_sandbox_probe(struct udevice *udev)
156{
157 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
158 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
159
160 /* fake some information for testing */
161 priv->device_features = VIRTIO_F_VERSION_1;
162 uc_priv->device = VIRTIO_ID_BLOCK;
163 uc_priv->vendor = ('u' << 24) | ('b' << 16) | ('o' << 8) | 't';
164
165 return 0;
166}
167
168/* check virtio device driver's remove routine was called to reset the device */
169static int virtio_sandbox_child_post_remove(struct udevice *vdev)
170{
171 u8 status;
172
173 virtio_get_status(vdev, &status);
174 if (status)
175 panic("virtio device was not reset\n");
176
177 return 0;
178}
179
180static const struct dm_virtio_ops virtio_sandbox1_ops = {
181 .get_config = virtio_sandbox_get_config,
182 .set_config = virtio_sandbox_set_config,
183 .get_status = virtio_sandbox_get_status,
184 .set_status = virtio_sandbox_set_status,
185 .reset = virtio_sandbox_reset,
186 .get_features = virtio_sandbox_get_features,
187 .set_features = virtio_sandbox_set_features,
188 .find_vqs = virtio_sandbox_find_vqs,
189 .del_vqs = virtio_sandbox_del_vqs,
190 .notify = virtio_sandbox_notify,
191};
192
193static const struct udevice_id virtio_sandbox1_ids[] = {
194 { .compatible = "sandbox,virtio1" },
195 { }
196};
197
198U_BOOT_DRIVER(virtio_sandbox1) = {
199 .name = "virtio-sandbox1",
200 .id = UCLASS_VIRTIO,
201 .of_match = virtio_sandbox1_ids,
202 .ops = &virtio_sandbox1_ops,
203 .probe = virtio_sandbox_probe,
204 .child_post_remove = virtio_sandbox_child_post_remove,
205 .priv_auto_alloc_size = sizeof(struct virtio_sandbox_priv),
206};
207
208/* this one without notify op */
209static const struct dm_virtio_ops virtio_sandbox2_ops = {
210 .get_config = virtio_sandbox_get_config,
211 .set_config = virtio_sandbox_set_config,
212 .get_status = virtio_sandbox_get_status,
213 .set_status = virtio_sandbox_set_status,
214 .reset = virtio_sandbox_reset,
215 .get_features = virtio_sandbox_get_features,
216 .set_features = virtio_sandbox_set_features,
217 .find_vqs = virtio_sandbox_find_vqs,
218 .del_vqs = virtio_sandbox_del_vqs,
219};
220
221static const struct udevice_id virtio_sandbox2_ids[] = {
222 { .compatible = "sandbox,virtio2" },
223 { }
224};
225
226U_BOOT_DRIVER(virtio_sandbox2) = {
227 .name = "virtio-sandbox2",
228 .id = UCLASS_VIRTIO,
229 .of_match = virtio_sandbox2_ids,
230 .ops = &virtio_sandbox2_ops,
231 .probe = virtio_sandbox_probe,
232 .priv_auto_alloc_size = sizeof(struct virtio_sandbox_priv),
233};