xref: /openbmc/u-boot/drivers/virtio/virtio_mmio.c (revision 1d6edcbf)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4  * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5  *
6  * VirtIO memory-maped I/O transport driver
7  * Ported from Linux drivers/virtio/virtio_mmio.c
8  */
9 
10 #include <common.h>
11 #include <dm.h>
12 #include <virtio_types.h>
13 #include <virtio.h>
14 #include <virtio_ring.h>
15 #include <linux/compat.h>
16 #include <linux/io.h>
17 #include "virtio_mmio.h"
18 
virtio_mmio_get_config(struct udevice * udev,unsigned int offset,void * buf,unsigned int len)19 static int virtio_mmio_get_config(struct udevice *udev, unsigned int offset,
20 				  void *buf, unsigned int len)
21 {
22 	struct virtio_mmio_priv *priv = dev_get_priv(udev);
23 	void __iomem *base = priv->base + VIRTIO_MMIO_CONFIG;
24 	u8 b;
25 	__le16 w;
26 	__le32 l;
27 
28 	if (priv->version == 1) {
29 		u8 *ptr = buf;
30 		int i;
31 
32 		for (i = 0; i < len; i++)
33 			ptr[i] = readb(base + offset + i);
34 
35 		return 0;
36 	}
37 
38 	switch (len) {
39 	case 1:
40 		b = readb(base + offset);
41 		memcpy(buf, &b, sizeof(b));
42 		break;
43 	case 2:
44 		w = cpu_to_le16(readw(base + offset));
45 		memcpy(buf, &w, sizeof(w));
46 		break;
47 	case 4:
48 		l = cpu_to_le32(readl(base + offset));
49 		memcpy(buf, &l, sizeof(l));
50 		break;
51 	case 8:
52 		l = cpu_to_le32(readl(base + offset));
53 		memcpy(buf, &l, sizeof(l));
54 		l = cpu_to_le32(readl(base + offset + sizeof(l)));
55 		memcpy(buf + sizeof(l), &l, sizeof(l));
56 		break;
57 	default:
58 		WARN_ON(true);
59 	}
60 
61 	return 0;
62 }
63 
virtio_mmio_set_config(struct udevice * udev,unsigned int offset,const void * buf,unsigned int len)64 static int virtio_mmio_set_config(struct udevice *udev, unsigned int offset,
65 				  const void *buf, unsigned int len)
66 {
67 	struct virtio_mmio_priv *priv = dev_get_priv(udev);
68 	void __iomem *base = priv->base + VIRTIO_MMIO_CONFIG;
69 	u8 b;
70 	__le16 w;
71 	__le32 l;
72 
73 	if (priv->version == 1) {
74 		const u8 *ptr = buf;
75 		int i;
76 
77 		for (i = 0; i < len; i++)
78 			writeb(ptr[i], base + offset + i);
79 
80 		return 0;
81 	}
82 
83 	switch (len) {
84 	case 1:
85 		memcpy(&b, buf, sizeof(b));
86 		writeb(b, base + offset);
87 		break;
88 	case 2:
89 		memcpy(&w, buf, sizeof(w));
90 		writew(le16_to_cpu(w), base + offset);
91 		break;
92 	case 4:
93 		memcpy(&l, buf, sizeof(l));
94 		writel(le32_to_cpu(l), base + offset);
95 		break;
96 	case 8:
97 		memcpy(&l, buf, sizeof(l));
98 		writel(le32_to_cpu(l), base + offset);
99 		memcpy(&l, buf + sizeof(l), sizeof(l));
100 		writel(le32_to_cpu(l), base + offset + sizeof(l));
101 		break;
102 	default:
103 		WARN_ON(true);
104 	}
105 
106 	return 0;
107 }
108 
virtio_mmio_generation(struct udevice * udev,u32 * counter)109 static int virtio_mmio_generation(struct udevice *udev, u32 *counter)
110 {
111 	struct virtio_mmio_priv *priv = dev_get_priv(udev);
112 
113 	if (priv->version == 1)
114 		*counter = 0;
115 	else
116 		*counter = readl(priv->base + VIRTIO_MMIO_CONFIG_GENERATION);
117 
118 	return 0;
119 }
120 
virtio_mmio_get_status(struct udevice * udev,u8 * status)121 static int virtio_mmio_get_status(struct udevice *udev, u8 *status)
122 {
123 	struct virtio_mmio_priv *priv = dev_get_priv(udev);
124 
125 	*status = readl(priv->base + VIRTIO_MMIO_STATUS) & 0xff;
126 
127 	return 0;
128 }
129 
virtio_mmio_set_status(struct udevice * udev,u8 status)130 static int virtio_mmio_set_status(struct udevice *udev, u8 status)
131 {
132 	struct virtio_mmio_priv *priv = dev_get_priv(udev);
133 
134 	/* We should never be setting status to 0 */
135 	WARN_ON(status == 0);
136 
137 	writel(status, priv->base + VIRTIO_MMIO_STATUS);
138 
139 	return 0;
140 }
141 
virtio_mmio_reset(struct udevice * udev)142 static int virtio_mmio_reset(struct udevice *udev)
143 {
144 	struct virtio_mmio_priv *priv = dev_get_priv(udev);
145 
146 	/* 0 status means a reset */
147 	writel(0, priv->base + VIRTIO_MMIO_STATUS);
148 
149 	return 0;
150 }
151 
virtio_mmio_get_features(struct udevice * udev,u64 * features)152 static int virtio_mmio_get_features(struct udevice *udev, u64 *features)
153 {
154 	struct virtio_mmio_priv *priv = dev_get_priv(udev);
155 
156 	writel(1, priv->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
157 	*features = readl(priv->base + VIRTIO_MMIO_DEVICE_FEATURES);
158 	*features <<= 32;
159 
160 	writel(0, priv->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
161 	*features |= readl(priv->base + VIRTIO_MMIO_DEVICE_FEATURES);
162 
163 	return 0;
164 }
165 
virtio_mmio_set_features(struct udevice * udev)166 static int virtio_mmio_set_features(struct udevice *udev)
167 {
168 	struct virtio_mmio_priv *priv = dev_get_priv(udev);
169 	struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
170 
171 	/* Make sure there is are no mixed devices */
172 	if (priv->version == 2 && uc_priv->legacy) {
173 		debug("New virtio-mmio devices (version 2) must provide VIRTIO_F_VERSION_1 feature!\n");
174 		return -EINVAL;
175 	}
176 
177 	writel(1, priv->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
178 	writel((u32)(uc_priv->features >> 32),
179 	       priv->base + VIRTIO_MMIO_DRIVER_FEATURES);
180 
181 	writel(0, priv->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
182 	writel((u32)uc_priv->features,
183 	       priv->base + VIRTIO_MMIO_DRIVER_FEATURES);
184 
185 	return 0;
186 }
187 
virtio_mmio_setup_vq(struct udevice * udev,unsigned int index)188 static struct virtqueue *virtio_mmio_setup_vq(struct udevice *udev,
189 					      unsigned int index)
190 {
191 	struct virtio_mmio_priv *priv = dev_get_priv(udev);
192 	struct virtqueue *vq;
193 	unsigned int num;
194 	int err;
195 
196 	/* Select the queue we're interested in */
197 	writel(index, priv->base + VIRTIO_MMIO_QUEUE_SEL);
198 
199 	/* Queue shouldn't already be set up */
200 	if (readl(priv->base + (priv->version == 1 ?
201 	    VIRTIO_MMIO_QUEUE_PFN : VIRTIO_MMIO_QUEUE_READY))) {
202 		err = -ENOENT;
203 		goto error_available;
204 	}
205 
206 	num = readl(priv->base + VIRTIO_MMIO_QUEUE_NUM_MAX);
207 	if (num == 0) {
208 		err = -ENOENT;
209 		goto error_new_virtqueue;
210 	}
211 
212 	/* Create the vring */
213 	vq = vring_create_virtqueue(index, num, VIRTIO_MMIO_VRING_ALIGN, udev);
214 	if (!vq) {
215 		err = -ENOMEM;
216 		goto error_new_virtqueue;
217 	}
218 
219 	/* Activate the queue */
220 	writel(virtqueue_get_vring_size(vq),
221 	       priv->base + VIRTIO_MMIO_QUEUE_NUM);
222 	if (priv->version == 1) {
223 		u64 q_pfn = virtqueue_get_desc_addr(vq) >> PAGE_SHIFT;
224 
225 		/*
226 		 * virtio-mmio v1 uses a 32bit QUEUE PFN. If we have something
227 		 * that doesn't fit in 32bit, fail the setup rather than
228 		 * pretending to be successful.
229 		 */
230 		if (q_pfn >> 32) {
231 			debug("platform bug: legacy virtio-mmio must not be used with RAM above 0x%llxGB\n",
232 			      0x1ULL << (32 + PAGE_SHIFT - 30));
233 			err = -E2BIG;
234 			goto error_bad_pfn;
235 		}
236 
237 		writel(PAGE_SIZE, priv->base + VIRTIO_MMIO_QUEUE_ALIGN);
238 		writel(q_pfn, priv->base + VIRTIO_MMIO_QUEUE_PFN);
239 	} else {
240 		u64 addr;
241 
242 		addr = virtqueue_get_desc_addr(vq);
243 		writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_DESC_LOW);
244 		writel((u32)(addr >> 32),
245 		       priv->base + VIRTIO_MMIO_QUEUE_DESC_HIGH);
246 
247 		addr = virtqueue_get_avail_addr(vq);
248 		writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW);
249 		writel((u32)(addr >> 32),
250 		       priv->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH);
251 
252 		addr = virtqueue_get_used_addr(vq);
253 		writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_USED_LOW);
254 		writel((u32)(addr >> 32),
255 		       priv->base + VIRTIO_MMIO_QUEUE_USED_HIGH);
256 
257 		writel(1, priv->base + VIRTIO_MMIO_QUEUE_READY);
258 	}
259 
260 	return vq;
261 
262 error_bad_pfn:
263 	vring_del_virtqueue(vq);
264 
265 error_new_virtqueue:
266 	if (priv->version == 1) {
267 		writel(0, priv->base + VIRTIO_MMIO_QUEUE_PFN);
268 	} else {
269 		writel(0, priv->base + VIRTIO_MMIO_QUEUE_READY);
270 		WARN_ON(readl(priv->base + VIRTIO_MMIO_QUEUE_READY));
271 	}
272 
273 error_available:
274 	return ERR_PTR(err);
275 }
276 
virtio_mmio_del_vq(struct virtqueue * vq)277 static void virtio_mmio_del_vq(struct virtqueue *vq)
278 {
279 	struct virtio_mmio_priv *priv = dev_get_priv(vq->vdev);
280 	unsigned int index = vq->index;
281 
282 	/* Select and deactivate the queue */
283 	writel(index, priv->base + VIRTIO_MMIO_QUEUE_SEL);
284 	if (priv->version == 1) {
285 		writel(0, priv->base + VIRTIO_MMIO_QUEUE_PFN);
286 	} else {
287 		writel(0, priv->base + VIRTIO_MMIO_QUEUE_READY);
288 		WARN_ON(readl(priv->base + VIRTIO_MMIO_QUEUE_READY));
289 	}
290 
291 	vring_del_virtqueue(vq);
292 }
293 
virtio_mmio_del_vqs(struct udevice * udev)294 static int virtio_mmio_del_vqs(struct udevice *udev)
295 {
296 	struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
297 	struct virtqueue *vq, *n;
298 
299 	list_for_each_entry_safe(vq, n, &uc_priv->vqs, list)
300 		virtio_mmio_del_vq(vq);
301 
302 	return 0;
303 }
304 
virtio_mmio_find_vqs(struct udevice * udev,unsigned int nvqs,struct virtqueue * vqs[])305 static int virtio_mmio_find_vqs(struct udevice *udev, unsigned int nvqs,
306 				struct virtqueue *vqs[])
307 {
308 	int i;
309 
310 	for (i = 0; i < nvqs; ++i) {
311 		vqs[i] = virtio_mmio_setup_vq(udev, i);
312 		if (IS_ERR(vqs[i])) {
313 			virtio_mmio_del_vqs(udev);
314 			return PTR_ERR(vqs[i]);
315 		}
316 	}
317 
318 	return 0;
319 }
320 
virtio_mmio_notify(struct udevice * udev,struct virtqueue * vq)321 static int virtio_mmio_notify(struct udevice *udev, struct virtqueue *vq)
322 {
323 	struct virtio_mmio_priv *priv = dev_get_priv(udev);
324 
325 	/*
326 	 * We write the queue's selector into the notification register
327 	 * to signal the other end
328 	 */
329 	writel(vq->index, priv->base + VIRTIO_MMIO_QUEUE_NOTIFY);
330 
331 	return 0;
332 }
333 
virtio_mmio_ofdata_to_platdata(struct udevice * udev)334 static int virtio_mmio_ofdata_to_platdata(struct udevice *udev)
335 {
336 	struct virtio_mmio_priv *priv = dev_get_priv(udev);
337 
338 	priv->base = (void __iomem *)(ulong)dev_read_addr(udev);
339 	if (priv->base == (void __iomem *)FDT_ADDR_T_NONE)
340 		return -EINVAL;
341 
342 	return 0;
343 }
344 
virtio_mmio_probe(struct udevice * udev)345 static int virtio_mmio_probe(struct udevice *udev)
346 {
347 	struct virtio_mmio_priv *priv = dev_get_priv(udev);
348 	struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
349 	u32 magic;
350 
351 	/* Check magic value */
352 	magic = readl(priv->base + VIRTIO_MMIO_MAGIC_VALUE);
353 	if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) {
354 		debug("(%s): wrong magic value 0x%08x!\n", udev->name, magic);
355 		return 0;
356 	}
357 
358 	/* Check device version */
359 	priv->version = readl(priv->base + VIRTIO_MMIO_VERSION);
360 	if (priv->version < 1 || priv->version > 2) {
361 		debug("(%s): version %d not supported!\n",
362 		      udev->name, priv->version);
363 		return 0;
364 	}
365 
366 	/* Check devicd ID */
367 	uc_priv->device = readl(priv->base + VIRTIO_MMIO_DEVICE_ID);
368 	if (uc_priv->device == 0) {
369 		/*
370 		 * virtio-mmio device with an ID 0 is a (dummy) placeholder
371 		 * with no function. End probing now with no error reported.
372 		 */
373 		return 0;
374 	}
375 	uc_priv->vendor = readl(priv->base + VIRTIO_MMIO_VENDOR_ID);
376 
377 	if (priv->version == 1)
378 		writel(PAGE_SIZE, priv->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
379 
380 	debug("(%s): device (%d) vendor (%08x) version (%d)\n", udev->name,
381 	      uc_priv->device, uc_priv->vendor, priv->version);
382 
383 	return 0;
384 }
385 
386 static const struct dm_virtio_ops virtio_mmio_ops = {
387 	.get_config	= virtio_mmio_get_config,
388 	.set_config	= virtio_mmio_set_config,
389 	.generation	= virtio_mmio_generation,
390 	.get_status	= virtio_mmio_get_status,
391 	.set_status	= virtio_mmio_set_status,
392 	.reset		= virtio_mmio_reset,
393 	.get_features	= virtio_mmio_get_features,
394 	.set_features	= virtio_mmio_set_features,
395 	.find_vqs	= virtio_mmio_find_vqs,
396 	.del_vqs	= virtio_mmio_del_vqs,
397 	.notify		= virtio_mmio_notify,
398 };
399 
400 static const struct udevice_id virtio_mmio_ids[] = {
401 	{ .compatible = "virtio,mmio" },
402 	{ }
403 };
404 
405 U_BOOT_DRIVER(virtio_mmio) = {
406 	.name	= "virtio-mmio",
407 	.id	= UCLASS_VIRTIO,
408 	.of_match = virtio_mmio_ids,
409 	.ops	= &virtio_mmio_ops,
410 	.probe	= virtio_mmio_probe,
411 	.ofdata_to_platdata = virtio_mmio_ofdata_to_platdata,
412 	.priv_auto_alloc_size = sizeof(struct virtio_mmio_priv),
413 };
414