aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTuomas Tynkkynen2018-10-15 04:21:11 -0500
committerSimon Glass2018-11-14 11:16:27 -0600
commitf4802209e59da759b2d1bfcf136d6855984a5d05 (patch)
tree31194bd1811f0efc4792c4f763375fead29d1c21
parent4ad54ec4d5c98a297f8df2fe9a630a534557f717 (diff)
downloadu-boot-f4802209e59da759b2d1bfcf136d6855984a5d05.tar.gz
u-boot-f4802209e59da759b2d1bfcf136d6855984a5d05.tar.xz
u-boot-f4802209e59da759b2d1bfcf136d6855984a5d05.zip
virtio: Add block driver support
This adds virtio block device driver support. Signed-off-by: Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi> Signed-off-by: Bin Meng <bmeng.cn@gmail.com> Reviewed-by: Simon Glass <sjg@chromium.org>
-rw-r--r--drivers/virtio/Kconfig7
-rw-r--r--drivers/virtio/Makefile1
-rw-r--r--drivers/virtio/virtio_blk.c137
-rw-r--r--drivers/virtio/virtio_blk.h129
4 files changed, 274 insertions, 0 deletions
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index e20dd69395..b72477ae28 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -36,4 +36,11 @@ config VIRTIO_NET
36 This is the virtual net driver for virtio. It can be used with 36 This is the virtual net driver for virtio. It can be used with
37 QEMU based targets. 37 QEMU based targets.
38 38
39config VIRTIO_BLK
40 bool "virtio block driver"
41 depends on VIRTIO
42 help
43 This is the virtual block driver for virtio. It can be used with
44 QEMU based targets.
45
39endmenu 46endmenu
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index b7764f161e..5fe742815b 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -6,3 +6,4 @@
6obj-y += virtio-uclass.o virtio_ring.o 6obj-y += virtio-uclass.o virtio_ring.o
7obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o 7obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o
8obj-$(CONFIG_VIRTIO_NET) += virtio_net.o 8obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
9obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
diff --git a/drivers/virtio/virtio_blk.c b/drivers/virtio/virtio_blk.c
new file mode 100644
index 0000000000..e793e34e83
--- /dev/null
+++ b/drivers/virtio/virtio_blk.c
@@ -0,0 +1,137 @@
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
7#include <common.h>
8#include <blk.h>
9#include <dm.h>
10#include <virtio_types.h>
11#include <virtio.h>
12#include <virtio_ring.h>
13#include "virtio_blk.h"
14
15struct virtio_blk_priv {
16 struct virtqueue *vq;
17};
18
19static ulong virtio_blk_do_req(struct udevice *dev, u64 sector,
20 lbaint_t blkcnt, void *buffer, u32 type)
21{
22 struct virtio_blk_priv *priv = dev_get_priv(dev);
23 unsigned int num_out = 0, num_in = 0;
24 struct virtio_sg *sgs[3];
25 u8 status;
26 int ret;
27
28 struct virtio_blk_outhdr out_hdr = {
29 .type = cpu_to_virtio32(dev, type),
30 .sector = cpu_to_virtio64(dev, sector),
31 };
32 struct virtio_sg hdr_sg = { &out_hdr, sizeof(out_hdr) };
33 struct virtio_sg data_sg = { buffer, blkcnt * 512 };
34 struct virtio_sg status_sg = { &status, sizeof(status) };
35
36 sgs[num_out++] = &hdr_sg;
37
38 if (type & VIRTIO_BLK_T_OUT)
39 sgs[num_out++] = &data_sg;
40 else
41 sgs[num_out + num_in++] = &data_sg;
42
43 sgs[num_out + num_in++] = &status_sg;
44
45 ret = virtqueue_add(priv->vq, sgs, num_out, num_in);
46 if (ret)
47 return ret;
48
49 virtqueue_kick(priv->vq);
50
51 while (!virtqueue_get_buf(priv->vq, NULL))
52 ;
53
54 return status == VIRTIO_BLK_S_OK ? blkcnt : -EIO;
55}
56
57static ulong virtio_blk_read(struct udevice *dev, lbaint_t start,
58 lbaint_t blkcnt, void *buffer)
59{
60 return virtio_blk_do_req(dev, start, blkcnt, buffer,
61 VIRTIO_BLK_T_IN);
62}
63
64static ulong virtio_blk_write(struct udevice *dev, lbaint_t start,
65 lbaint_t blkcnt, const void *buffer)
66{
67 return virtio_blk_do_req(dev, start, blkcnt, (void *)buffer,
68 VIRTIO_BLK_T_OUT);
69}
70
71static int virtio_blk_bind(struct udevice *dev)
72{
73 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev->parent);
74 struct blk_desc *desc = dev_get_uclass_platdata(dev);
75 int devnum;
76
77 desc->if_type = IF_TYPE_VIRTIO;
78 /*
79 * Initialize the devnum to -ENODEV. This is to make sure that
80 * blk_next_free_devnum() works as expected, since the default
81 * value 0 is a valid devnum.
82 */
83 desc->devnum = -ENODEV;
84 devnum = blk_next_free_devnum(IF_TYPE_VIRTIO);
85 if (devnum < 0)
86 return devnum;
87 desc->devnum = devnum;
88 desc->part_type = PART_TYPE_UNKNOWN;
89 /*
90 * virtio mmio transport supplies string identification for us,
91 * while pci trnasport uses a 2-byte subvendor value.
92 */
93 if (uc_priv->vendor >> 16)
94 sprintf(desc->vendor, "%s", (char *)&uc_priv->vendor);
95 else
96 sprintf(desc->vendor, "%04x", uc_priv->vendor);
97 desc->bdev = dev;
98
99 /* Indicate what driver features we support */
100 virtio_driver_features_init(uc_priv, NULL, 0, NULL, 0);
101
102 return 0;
103}
104
105static int virtio_blk_probe(struct udevice *dev)
106{
107 struct virtio_blk_priv *priv = dev_get_priv(dev);
108 struct blk_desc *desc = dev_get_uclass_platdata(dev);
109 u64 cap;
110 int ret;
111
112 ret = virtio_find_vqs(dev, 1, &priv->vq);
113 if (ret)
114 return ret;
115
116 desc->blksz = 512;
117 virtio_cread(dev, struct virtio_blk_config, capacity, &cap);
118 desc->lba = cap;
119
120 return 0;
121}
122
123static const struct blk_ops virtio_blk_ops = {
124 .read = virtio_blk_read,
125 .write = virtio_blk_write,
126};
127
128U_BOOT_DRIVER(virtio_blk) = {
129 .name = VIRTIO_BLK_DRV_NAME,
130 .id = UCLASS_BLK,
131 .ops = &virtio_blk_ops,
132 .bind = virtio_blk_bind,
133 .probe = virtio_blk_probe,
134 .remove = virtio_reset,
135 .priv_auto_alloc_size = sizeof(struct virtio_blk_priv),
136 .flags = DM_FLAG_ACTIVE_DMA,
137};
diff --git a/drivers/virtio/virtio_blk.h b/drivers/virtio/virtio_blk.h
new file mode 100644
index 0000000000..8d8e02fa2e
--- /dev/null
+++ b/drivers/virtio/virtio_blk.h
@@ -0,0 +1,129 @@
1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 *
6 * From Linux kernel include/uapi/linux/virtio_blk.h
7 */
8
9#ifndef _LINUX_VIRTIO_BLK_H
10#define _LINUX_VIRTIO_BLK_H
11
12/* Feature bits */
13#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */
14#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */
15#define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */
16#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
17#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available */
18#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */
19#define VIRTIO_BLK_F_MQ 12 /* Support more than one vq */
20
21/* Legacy feature bits */
22#ifndef VIRTIO_BLK_NO_LEGACY
23#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */
24#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
25#define VIRTIO_BLK_F_FLUSH 9 /* Flush command supported */
26#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */
27#ifndef __KERNEL__
28/* Old (deprecated) name for VIRTIO_BLK_F_FLUSH */
29#define VIRTIO_BLK_F_WCE VIRTIO_BLK_F_FLUSH
30#endif
31#endif /* !VIRTIO_BLK_NO_LEGACY */
32
33#define VIRTIO_BLK_ID_BYTES 20 /* ID string length */
34
35struct __packed virtio_blk_config {
36 /* The capacity (in 512-byte sectors) */
37 __u64 capacity;
38 /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */
39 __u32 size_max;
40 /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
41 __u32 seg_max;
42 /* geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
43 struct virtio_blk_geometry {
44 __u16 cylinders;
45 __u8 heads;
46 __u8 sectors;
47 } geometry;
48
49 /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
50 __u32 blk_size;
51
52 /* the next 4 entries are guarded by VIRTIO_BLK_F_TOPOLOGY */
53 /* exponent for physical block per logical block */
54 __u8 physical_block_exp;
55 /* alignment offset in logical blocks */
56 __u8 alignment_offset;
57 /* minimum I/O size without performance penalty in logical blocks */
58 __u16 min_io_size;
59 /* optimal sustained I/O size in logical blocks */
60 __u32 opt_io_size;
61
62 /* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */
63 __u8 wce;
64 __u8 unused;
65
66 /* number of vqs, only available when VIRTIO_BLK_F_MQ is set */
67 __u16 num_queues;
68};
69
70/*
71 * Command types
72 *
73 * Usage is a bit tricky as some bits are used as flags and some are not.
74 *
75 * Rules:
76 * VIRTIO_BLK_T_OUT may be combined with VIRTIO_BLK_T_SCSI_CMD or
77 * VIRTIO_BLK_T_BARRIER. VIRTIO_BLK_T_FLUSH is a command of its own
78 * and may not be combined with any of the other flags.
79 */
80
81/* These two define direction */
82#define VIRTIO_BLK_T_IN 0
83#define VIRTIO_BLK_T_OUT 1
84
85#ifndef VIRTIO_BLK_NO_LEGACY
86/* This bit says it's a scsi command, not an actual read or write */
87#define VIRTIO_BLK_T_SCSI_CMD 2
88#endif /* VIRTIO_BLK_NO_LEGACY */
89
90/* Cache flush command */
91#define VIRTIO_BLK_T_FLUSH 4
92
93/* Get device ID command */
94#define VIRTIO_BLK_T_GET_ID 8
95
96#ifndef VIRTIO_BLK_NO_LEGACY
97/* Barrier before this op */
98#define VIRTIO_BLK_T_BARRIER 0x80000000
99#endif /* !VIRTIO_BLK_NO_LEGACY */
100
101/*
102 * This comes first in the read scatter-gather list.
103 * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated,
104 * this is the first element of the read scatter-gather list.
105 */
106struct virtio_blk_outhdr {
107 /* VIRTIO_BLK_T* */
108 __virtio32 type;
109 /* io priority */
110 __virtio32 ioprio;
111 /* Sector (ie. 512 byte offset) */
112 __virtio64 sector;
113};
114
115#ifndef VIRTIO_BLK_NO_LEGACY
116struct virtio_scsi_inhdr {
117 __virtio32 errors;
118 __virtio32 data_len;
119 __virtio32 sense_len;
120 __virtio32 residual;
121};
122#endif /* !VIRTIO_BLK_NO_LEGACY */
123
124/* And this is the final byte of the write scatter-gather list */
125#define VIRTIO_BLK_S_OK 0
126#define VIRTIO_BLK_S_IOERR 1
127#define VIRTIO_BLK_S_UNSUPP 2
128
129#endif /* _LINUX_VIRTIO_BLK_H */