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 }; 234