]>
Commit | Line | Data |
---|---|---|
640aae0f BM |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) 2018, Bin Meng <[email protected]> | |
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> | |
eb41d8a1 | 13 | #include <linux/bug.h> |
640aae0f | 14 | #include <linux/compat.h> |
61b29b82 | 15 | #include <linux/err.h> |
640aae0f BM |
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 */ | |
1674b6c4 | 163 | priv->device_features = BIT_ULL(VIRTIO_F_VERSION_1); |
00fc8cad SG |
164 | uc_priv->device = dev_read_u32_default(udev, "virtio-type", |
165 | VIRTIO_ID_RNG); | |
640aae0f BM |
166 | uc_priv->vendor = ('u' << 24) | ('b' << 16) | ('o' << 8) | 't'; |
167 | ||
168 | return 0; | |
169 | } | |
170 | ||
640aae0f BM |
171 | static const struct dm_virtio_ops virtio_sandbox1_ops = { |
172 | .get_config = virtio_sandbox_get_config, | |
173 | .set_config = virtio_sandbox_set_config, | |
174 | .get_status = virtio_sandbox_get_status, | |
175 | .set_status = virtio_sandbox_set_status, | |
176 | .reset = virtio_sandbox_reset, | |
177 | .get_features = virtio_sandbox_get_features, | |
178 | .set_features = virtio_sandbox_set_features, | |
179 | .find_vqs = virtio_sandbox_find_vqs, | |
180 | .del_vqs = virtio_sandbox_del_vqs, | |
181 | .notify = virtio_sandbox_notify, | |
182 | }; | |
183 | ||
184 | static const struct udevice_id virtio_sandbox1_ids[] = { | |
185 | { .compatible = "sandbox,virtio1" }, | |
186 | { } | |
187 | }; | |
188 | ||
189 | U_BOOT_DRIVER(virtio_sandbox1) = { | |
190 | .name = "virtio-sandbox1", | |
191 | .id = UCLASS_VIRTIO, | |
192 | .of_match = virtio_sandbox1_ids, | |
193 | .ops = &virtio_sandbox1_ops, | |
194 | .probe = virtio_sandbox_probe, | |
41575d8e | 195 | .priv_auto = sizeof(struct virtio_sandbox_priv), |
640aae0f BM |
196 | }; |
197 | ||
198 | /* this one without notify op */ | |
199 | static const struct dm_virtio_ops virtio_sandbox2_ops = { | |
200 | .get_config = virtio_sandbox_get_config, | |
201 | .set_config = virtio_sandbox_set_config, | |
202 | .get_status = virtio_sandbox_get_status, | |
203 | .set_status = virtio_sandbox_set_status, | |
204 | .reset = virtio_sandbox_reset, | |
205 | .get_features = virtio_sandbox_get_features, | |
206 | .set_features = virtio_sandbox_set_features, | |
207 | .find_vqs = virtio_sandbox_find_vqs, | |
208 | .del_vqs = virtio_sandbox_del_vqs, | |
209 | }; | |
210 | ||
211 | static const struct udevice_id virtio_sandbox2_ids[] = { | |
212 | { .compatible = "sandbox,virtio2" }, | |
213 | { } | |
214 | }; | |
215 | ||
216 | U_BOOT_DRIVER(virtio_sandbox2) = { | |
217 | .name = "virtio-sandbox2", | |
218 | .id = UCLASS_VIRTIO, | |
219 | .of_match = virtio_sandbox2_ids, | |
220 | .ops = &virtio_sandbox2_ops, | |
221 | .probe = virtio_sandbox_probe, | |
41575d8e | 222 | .priv_auto = sizeof(struct virtio_sandbox_priv), |
640aae0f | 223 | }; |