diff options
| -rw-r--r-- | drivers/virtio/virtio_mmio.c | 131 | ||||
| -rw-r--r-- | include/linux/virtio_mmio.h | 44 |
2 files changed, 118 insertions, 57 deletions
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 00d115b22bd8..cad569890908 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Virtio memory mapped device driver | 2 | * Virtio memory mapped device driver |
| 3 | * | 3 | * |
| 4 | * Copyright 2011, ARM Ltd. | 4 | * Copyright 2011-2014, ARM Ltd. |
| 5 | * | 5 | * |
| 6 | * This module allows virtio devices to be used over a virtual, memory mapped | 6 | * This module allows virtio devices to be used over a virtual, memory mapped |
| 7 | * platform device. | 7 | * platform device. |
| @@ -50,36 +50,6 @@ | |||
| 50 | * | 50 | * |
| 51 | * | 51 | * |
| 52 | * | 52 | * |
| 53 | * Registers layout (all 32-bit wide): | ||
| 54 | * | ||
| 55 | * offset d. name description | ||
| 56 | * ------ -- ---------------- ----------------- | ||
| 57 | * | ||
| 58 | * 0x000 R MagicValue Magic value "virt" | ||
| 59 | * 0x004 R Version Device version (current max. 1) | ||
| 60 | * 0x008 R DeviceID Virtio device ID | ||
| 61 | * 0x00c R VendorID Virtio vendor ID | ||
| 62 | * | ||
| 63 | * 0x010 R HostFeatures Features supported by the host | ||
| 64 | * 0x014 W HostFeaturesSel Set of host features to access via HostFeatures | ||
| 65 | * | ||
| 66 | * 0x020 W GuestFeatures Features activated by the guest | ||
| 67 | * 0x024 W GuestFeaturesSel Set of activated features to set via GuestFeatures | ||
| 68 | * 0x028 W GuestPageSize Size of guest's memory page in bytes | ||
| 69 | * | ||
| 70 | * 0x030 W QueueSel Queue selector | ||
| 71 | * 0x034 R QueueNumMax Maximum size of the currently selected queue | ||
| 72 | * 0x038 W QueueNum Queue size for the currently selected queue | ||
| 73 | * 0x03c W QueueAlign Used Ring alignment for the current queue | ||
| 74 | * 0x040 RW QueuePFN PFN for the currently selected queue | ||
| 75 | * | ||
| 76 | * 0x050 W QueueNotify Queue notifier | ||
| 77 | * 0x060 R InterruptStatus Interrupt status register | ||
| 78 | * 0x064 W InterruptACK Interrupt acknowledge register | ||
| 79 | * 0x070 RW Status Device status register | ||
| 80 | * | ||
| 81 | * 0x100+ RW Device-specific configuration space | ||
| 82 | * | ||
| 83 | * Based on Virtio PCI driver by Anthony Liguori, copyright IBM Corp. 2007 | 53 | * Based on Virtio PCI driver by Anthony Liguori, copyright IBM Corp. 2007 |
| 84 | * | 54 | * |
| 85 | * This work is licensed under the terms of the GNU GPL, version 2 or later. | 55 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
| @@ -145,11 +115,16 @@ struct virtio_mmio_vq_info { | |||
| 145 | static u64 vm_get_features(struct virtio_device *vdev) | 115 | static u64 vm_get_features(struct virtio_device *vdev) |
| 146 | { | 116 | { |
| 147 | struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); | 117 | struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); |
| 118 | u64 features; | ||
| 119 | |||
| 120 | writel(1, vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL); | ||
| 121 | features = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES); | ||
| 122 | features <<= 32; | ||
| 148 | 123 | ||
| 149 | /* TODO: Features > 32 bits */ | 124 | writel(0, vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL); |
| 150 | writel(0, vm_dev->base + VIRTIO_MMIO_HOST_FEATURES_SEL); | 125 | features |= readl(vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES); |
| 151 | 126 | ||
| 152 | return readl(vm_dev->base + VIRTIO_MMIO_HOST_FEATURES); | 127 | return features; |
| 153 | } | 128 | } |
| 154 | 129 | ||
| 155 | static int vm_finalize_features(struct virtio_device *vdev) | 130 | static int vm_finalize_features(struct virtio_device *vdev) |
| @@ -159,11 +134,20 @@ static int vm_finalize_features(struct virtio_device *vdev) | |||
| 159 | /* Give virtio_ring a chance to accept features. */ | 134 | /* Give virtio_ring a chance to accept features. */ |
| 160 | vring_transport_features(vdev); | 135 | vring_transport_features(vdev); |
| 161 | 136 | ||
| 162 | /* Make sure we don't have any features > 32 bits! */ | 137 | /* Make sure there is are no mixed devices */ |
| 163 | BUG_ON((u32)vdev->features != vdev->features); | 138 | if (vm_dev->version == 2 && |
| 139 | !__virtio_test_bit(vdev, VIRTIO_F_VERSION_1)) { | ||
| 140 | dev_err(&vdev->dev, "New virtio-mmio devices (version 2) must provide VIRTIO_F_VERSION_1 feature!\n"); | ||
| 141 | return -EINVAL; | ||
| 142 | } | ||
| 143 | |||
| 144 | writel(1, vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL); | ||
| 145 | writel((u32)(vdev->features >> 32), | ||
| 146 | vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES); | ||
| 164 | 147 | ||
| 165 | writel(0, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES_SEL); | 148 | writel(0, vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL); |
| 166 | writel(vdev->features, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES); | 149 | writel((u32)vdev->features, |
| 150 | vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES); | ||
| 167 | 151 | ||
| 168 | return 0; | 152 | return 0; |
| 169 | } | 153 | } |
| @@ -275,7 +259,12 @@ static void vm_del_vq(struct virtqueue *vq) | |||
| 275 | 259 | ||
| 276 | /* Select and deactivate the queue */ | 260 | /* Select and deactivate the queue */ |
| 277 | writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL); | 261 | writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL); |
| 278 | writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); | 262 | if (vm_dev->version == 1) { |
| 263 | writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); | ||
| 264 | } else { | ||
| 265 | writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_READY); | ||
| 266 | WARN_ON(readl(vm_dev->base + VIRTIO_MMIO_QUEUE_READY)); | ||
| 267 | } | ||
| 279 | 268 | ||
| 280 | size = PAGE_ALIGN(vring_size(info->num, VIRTIO_MMIO_VRING_ALIGN)); | 269 | size = PAGE_ALIGN(vring_size(info->num, VIRTIO_MMIO_VRING_ALIGN)); |
| 281 | free_pages_exact(info->queue, size); | 270 | free_pages_exact(info->queue, size); |
| @@ -312,7 +301,8 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index, | |||
| 312 | writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL); | 301 | writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL); |
| 313 | 302 | ||
| 314 | /* Queue shouldn't already be set up. */ | 303 | /* Queue shouldn't already be set up. */ |
| 315 | if (readl(vm_dev->base + VIRTIO_MMIO_QUEUE_PFN)) { | 304 | if (readl(vm_dev->base + (vm_dev->version == 1 ? |
| 305 | VIRTIO_MMIO_QUEUE_PFN : VIRTIO_MMIO_QUEUE_READY))) { | ||
| 316 | err = -ENOENT; | 306 | err = -ENOENT; |
| 317 | goto error_available; | 307 | goto error_available; |
| 318 | } | 308 | } |
| @@ -356,13 +346,6 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index, | |||
| 356 | info->num /= 2; | 346 | info->num /= 2; |
| 357 | } | 347 | } |
| 358 | 348 | ||
| 359 | /* Activate the queue */ | ||
| 360 | writel(info->num, vm_dev->base + VIRTIO_MMIO_QUEUE_NUM); | ||
| 361 | writel(VIRTIO_MMIO_VRING_ALIGN, | ||
| 362 | vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN); | ||
| 363 | writel(virt_to_phys(info->queue) >> PAGE_SHIFT, | ||
| 364 | vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); | ||
| 365 | |||
| 366 | /* Create the vring */ | 349 | /* Create the vring */ |
| 367 | vq = vring_new_virtqueue(index, info->num, VIRTIO_MMIO_VRING_ALIGN, vdev, | 350 | vq = vring_new_virtqueue(index, info->num, VIRTIO_MMIO_VRING_ALIGN, vdev, |
| 368 | true, info->queue, vm_notify, callback, name); | 351 | true, info->queue, vm_notify, callback, name); |
| @@ -371,6 +354,33 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index, | |||
| 371 | goto error_new_virtqueue; | 354 | goto error_new_virtqueue; |
| 372 | } | 355 | } |
| 373 | 356 | ||
| 357 | /* Activate the queue */ | ||
| 358 | writel(info->num, vm_dev->base + VIRTIO_MMIO_QUEUE_NUM); | ||
| 359 | if (vm_dev->version == 1) { | ||
| 360 | writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN); | ||
| 361 | writel(virt_to_phys(info->queue) >> PAGE_SHIFT, | ||
| 362 | vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); | ||
| 363 | } else { | ||
| 364 | u64 addr; | ||
| 365 | |||
| 366 | addr = virt_to_phys(info->queue); | ||
| 367 | writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_LOW); | ||
| 368 | writel((u32)(addr >> 32), | ||
| 369 | vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_HIGH); | ||
| 370 | |||
| 371 | addr = virt_to_phys(virtqueue_get_avail(vq)); | ||
| 372 | writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW); | ||
| 373 | writel((u32)(addr >> 32), | ||
| 374 | vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH); | ||
| 375 | |||
| 376 | addr = virt_to_phys(virtqueue_get_used(vq)); | ||
| 377 | writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_USED_LOW); | ||
| 378 | writel((u32)(addr >> 32), | ||
| 379 | vm_dev->base + VIRTIO_MMIO_QUEUE_USED_HIGH); | ||
| 380 | |||
| 381 | writel(1, vm_dev->base + VIRTIO_MMIO_QUEUE_READY); | ||
| 382 | } | ||
| 383 | |||
| 374 | vq->priv = info; | 384 | vq->priv = info; |
| 375 | info->vq = vq; | 385 | info->vq = vq; |
| 376 | 386 | ||
| @@ -381,7 +391,12 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index, | |||
| 381 | return vq; | 391 | return vq; |
| 382 | 392 | ||
| 383 | error_new_virtqueue: | 393 | error_new_virtqueue: |
| 384 | writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); | 394 | if (vm_dev->version == 1) { |
| 395 | writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); | ||
| 396 | } else { | ||
| 397 | writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_READY); | ||
| 398 | WARN_ON(readl(vm_dev->base + VIRTIO_MMIO_QUEUE_READY)); | ||
| 399 | } | ||
| 385 | free_pages_exact(info->queue, size); | 400 | free_pages_exact(info->queue, size); |
| 386 | error_alloc_pages: | 401 | error_alloc_pages: |
| 387 | kfree(info); | 402 | kfree(info); |
| @@ -476,16 +491,32 @@ static int virtio_mmio_probe(struct platform_device *pdev) | |||
| 476 | 491 | ||
| 477 | /* Check device version */ | 492 | /* Check device version */ |
| 478 | vm_dev->version = readl(vm_dev->base + VIRTIO_MMIO_VERSION); | 493 | vm_dev->version = readl(vm_dev->base + VIRTIO_MMIO_VERSION); |
| 479 | if (vm_dev->version != 1) { | 494 | if (vm_dev->version < 1 || vm_dev->version > 2) { |
| 480 | dev_err(&pdev->dev, "Version %ld not supported!\n", | 495 | dev_err(&pdev->dev, "Version %ld not supported!\n", |
| 481 | vm_dev->version); | 496 | vm_dev->version); |
| 482 | return -ENXIO; | 497 | return -ENXIO; |
| 483 | } | 498 | } |
| 484 | 499 | ||
| 485 | vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID); | 500 | vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID); |
| 501 | if (vm_dev->vdev.id.device == 0) { | ||
| 502 | /* | ||
| 503 | * virtio-mmio device with an ID 0 is a (dummy) placeholder | ||
| 504 | * with no function. End probing now with no error reported. | ||
| 505 | */ | ||
| 506 | return -ENODEV; | ||
| 507 | } | ||
| 486 | vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID); | 508 | vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID); |
| 487 | 509 | ||
| 488 | writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE); | 510 | /* Reject legacy-only IDs for version 2 devices */ |
| 511 | if (vm_dev->version == 2 && | ||
| 512 | virtio_device_is_legacy_only(vm_dev->vdev.id)) { | ||
| 513 | dev_err(&pdev->dev, "Version 2 not supported for devices %u!\n", | ||
| 514 | vm_dev->vdev.id.device); | ||
| 515 | return -ENODEV; | ||
| 516 | } | ||
| 517 | |||
| 518 | if (vm_dev->version == 1) | ||
| 519 | writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE); | ||
| 489 | 520 | ||
| 490 | platform_set_drvdata(pdev, vm_dev); | 521 | platform_set_drvdata(pdev, vm_dev); |
| 491 | 522 | ||
diff --git a/include/linux/virtio_mmio.h b/include/linux/virtio_mmio.h index 5c7b6f0daef8..c4b09689ab64 100644 --- a/include/linux/virtio_mmio.h +++ b/include/linux/virtio_mmio.h | |||
| @@ -51,23 +51,29 @@ | |||
| 51 | /* Virtio vendor ID - Read Only */ | 51 | /* Virtio vendor ID - Read Only */ |
| 52 | #define VIRTIO_MMIO_VENDOR_ID 0x00c | 52 | #define VIRTIO_MMIO_VENDOR_ID 0x00c |
| 53 | 53 | ||
| 54 | /* Bitmask of the features supported by the host | 54 | /* Bitmask of the features supported by the device (host) |
| 55 | * (32 bits per set) - Read Only */ | 55 | * (32 bits per set) - Read Only */ |
| 56 | #define VIRTIO_MMIO_HOST_FEATURES 0x010 | 56 | #define VIRTIO_MMIO_DEVICE_FEATURES 0x010 |
| 57 | 57 | ||
| 58 | /* Host features set selector - Write Only */ | 58 | /* Device (host) features set selector - Write Only */ |
| 59 | #define VIRTIO_MMIO_HOST_FEATURES_SEL 0x014 | 59 | #define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014 |
| 60 | 60 | ||
| 61 | /* Bitmask of features activated by the guest | 61 | /* Bitmask of features activated by the driver (guest) |
| 62 | * (32 bits per set) - Write Only */ | 62 | * (32 bits per set) - Write Only */ |
| 63 | #define VIRTIO_MMIO_GUEST_FEATURES 0x020 | 63 | #define VIRTIO_MMIO_DRIVER_FEATURES 0x020 |
| 64 | 64 | ||
| 65 | /* Activated features set selector - Write Only */ | 65 | /* Activated features set selector - Write Only */ |
| 66 | #define VIRTIO_MMIO_GUEST_FEATURES_SEL 0x024 | 66 | #define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024 |
| 67 | |||
| 68 | |||
| 69 | #ifndef VIRTIO_MMIO_NO_LEGACY /* LEGACY DEVICES ONLY! */ | ||
| 67 | 70 | ||
| 68 | /* Guest's memory page size in bytes - Write Only */ | 71 | /* Guest's memory page size in bytes - Write Only */ |
| 69 | #define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 | 72 | #define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 |
| 70 | 73 | ||
| 74 | #endif | ||
| 75 | |||
| 76 | |||
| 71 | /* Queue selector - Write Only */ | 77 | /* Queue selector - Write Only */ |
| 72 | #define VIRTIO_MMIO_QUEUE_SEL 0x030 | 78 | #define VIRTIO_MMIO_QUEUE_SEL 0x030 |
| 73 | 79 | ||
| @@ -77,12 +83,21 @@ | |||
| 77 | /* Queue size for the currently selected queue - Write Only */ | 83 | /* Queue size for the currently selected queue - Write Only */ |
| 78 | #define VIRTIO_MMIO_QUEUE_NUM 0x038 | 84 | #define VIRTIO_MMIO_QUEUE_NUM 0x038 |
| 79 | 85 | ||
| 86 | |||
| 87 | #ifndef VIRTIO_MMIO_NO_LEGACY /* LEGACY DEVICES ONLY! */ | ||
| 88 | |||
| 80 | /* Used Ring alignment for the currently selected queue - Write Only */ | 89 | /* Used Ring alignment for the currently selected queue - Write Only */ |
| 81 | #define VIRTIO_MMIO_QUEUE_ALIGN 0x03c | 90 | #define VIRTIO_MMIO_QUEUE_ALIGN 0x03c |
| 82 | 91 | ||
| 83 | /* Guest's PFN for the currently selected queue - Read Write */ | 92 | /* Guest's PFN for the currently selected queue - Read Write */ |
| 84 | #define VIRTIO_MMIO_QUEUE_PFN 0x040 | 93 | #define VIRTIO_MMIO_QUEUE_PFN 0x040 |
| 85 | 94 | ||
| 95 | #endif | ||
| 96 | |||
| 97 | |||
| 98 | /* Ready bit for the currently selected queue - Read Write */ | ||
| 99 | #define VIRTIO_MMIO_QUEUE_READY 0x044 | ||
| 100 | |||
| 86 | /* Queue notifier - Write Only */ | 101 | /* Queue notifier - Write Only */ |
| 87 | #define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 | 102 | #define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 |
| 88 | 103 | ||
| @@ -95,6 +110,21 @@ | |||
| 95 | /* Device status register - Read Write */ | 110 | /* Device status register - Read Write */ |
| 96 | #define VIRTIO_MMIO_STATUS 0x070 | 111 | #define VIRTIO_MMIO_STATUS 0x070 |
| 97 | 112 | ||
| 113 | /* Selected queue's Descriptor Table address, 64 bits in two halves */ | ||
| 114 | #define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 | ||
| 115 | #define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084 | ||
| 116 | |||
| 117 | /* Selected queue's Available Ring address, 64 bits in two halves */ | ||
| 118 | #define VIRTIO_MMIO_QUEUE_AVAIL_LOW 0x090 | ||
| 119 | #define VIRTIO_MMIO_QUEUE_AVAIL_HIGH 0x094 | ||
| 120 | |||
| 121 | /* Selected queue's Used Ring address, 64 bits in two halves */ | ||
| 122 | #define VIRTIO_MMIO_QUEUE_USED_LOW 0x0a0 | ||
| 123 | #define VIRTIO_MMIO_QUEUE_USED_HIGH 0x0a4 | ||
| 124 | |||
| 125 | /* Configuration atomicity value */ | ||
| 126 | #define VIRTIO_MMIO_CONFIG_GENERATION 0x0fc | ||
| 127 | |||
| 98 | /* The config space is defined by each driver as | 128 | /* The config space is defined by each driver as |
| 99 | * the per-driver configuration space - Read Write */ | 129 | * the per-driver configuration space - Read Write */ |
| 100 | #define VIRTIO_MMIO_CONFIG 0x100 | 130 | #define VIRTIO_MMIO_CONFIG 0x100 |
