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