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