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