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