Merge tag 'ti-v2020.07-rc3' of https://gitlab.denx.de/u-boot/custodians/u-boot-ti
[oweals/u-boot.git] / drivers / virtio / virtio_sandbox.c
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
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
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
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
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
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
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
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
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
120 static void virtio_sandbox_del_vq(struct virtqueue *vq)
121 {
122         vring_del_virtqueue(vq);
123 }
124
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
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
152 static int virtio_sandbox_notify(struct udevice *udev, struct virtqueue *vq)
153 {
154         return 0;
155 }
156
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 = VIRTIO_F_VERSION_1;
164         uc_priv->device = VIRTIO_ID_BLOCK;
165         uc_priv->vendor = ('u' << 24) | ('b' << 16) | ('o' << 8) | 't';
166
167         return 0;
168 }
169
170 /* check virtio device driver's remove routine was called to reset the device */
171 static int virtio_sandbox_child_post_remove(struct udevice *vdev)
172 {
173         u8 status;
174
175         virtio_get_status(vdev, &status);
176         if (status)
177                 panic("virtio device was not reset\n");
178
179         return 0;
180 }
181
182 static const struct dm_virtio_ops virtio_sandbox1_ops = {
183         .get_config     = virtio_sandbox_get_config,
184         .set_config     = virtio_sandbox_set_config,
185         .get_status     = virtio_sandbox_get_status,
186         .set_status     = virtio_sandbox_set_status,
187         .reset          = virtio_sandbox_reset,
188         .get_features   = virtio_sandbox_get_features,
189         .set_features   = virtio_sandbox_set_features,
190         .find_vqs       = virtio_sandbox_find_vqs,
191         .del_vqs        = virtio_sandbox_del_vqs,
192         .notify         = virtio_sandbox_notify,
193 };
194
195 static const struct udevice_id virtio_sandbox1_ids[] = {
196         { .compatible = "sandbox,virtio1" },
197         { }
198 };
199
200 U_BOOT_DRIVER(virtio_sandbox1) = {
201         .name   = "virtio-sandbox1",
202         .id     = UCLASS_VIRTIO,
203         .of_match = virtio_sandbox1_ids,
204         .ops    = &virtio_sandbox1_ops,
205         .probe  = virtio_sandbox_probe,
206         .child_post_remove = virtio_sandbox_child_post_remove,
207         .priv_auto_alloc_size = sizeof(struct virtio_sandbox_priv),
208 };
209
210 /* this one without notify op */
211 static const struct dm_virtio_ops virtio_sandbox2_ops = {
212         .get_config     = virtio_sandbox_get_config,
213         .set_config     = virtio_sandbox_set_config,
214         .get_status     = virtio_sandbox_get_status,
215         .set_status     = virtio_sandbox_set_status,
216         .reset          = virtio_sandbox_reset,
217         .get_features   = virtio_sandbox_get_features,
218         .set_features   = virtio_sandbox_set_features,
219         .find_vqs       = virtio_sandbox_find_vqs,
220         .del_vqs        = virtio_sandbox_del_vqs,
221 };
222
223 static const struct udevice_id virtio_sandbox2_ids[] = {
224         { .compatible = "sandbox,virtio2" },
225         { }
226 };
227
228 U_BOOT_DRIVER(virtio_sandbox2) = {
229         .name   = "virtio-sandbox2",
230         .id     = UCLASS_VIRTIO,
231         .of_match = virtio_sandbox2_ids,
232         .ops    = &virtio_sandbox2_ops,
233         .probe  = virtio_sandbox_probe,
234         .priv_auto_alloc_size = sizeof(struct virtio_sandbox_priv),
235 };