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