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