18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Virtio PCI driver - legacy device support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This module allows virtio devices to be used over a virtual PCI device. 68c2ecf20Sopenharmony_ci * This can be used with QEMU based VMMs like KVM or Xen. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright IBM Corp. 2007 98c2ecf20Sopenharmony_ci * Copyright Red Hat, Inc. 2014 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Authors: 128c2ecf20Sopenharmony_ci * Anthony Liguori <aliguori@us.ibm.com> 138c2ecf20Sopenharmony_ci * Rusty Russell <rusty@rustcorp.com.au> 148c2ecf20Sopenharmony_ci * Michael S. Tsirkin <mst@redhat.com> 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "virtio_pci_common.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* virtio config->get_features() implementation */ 208c2ecf20Sopenharmony_cistatic u64 vp_get_features(struct virtio_device *vdev) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci /* When someone needs more than 32 feature bits, we'll need to 258c2ecf20Sopenharmony_ci * steal a bit to indicate that the rest are somewhere else. */ 268c2ecf20Sopenharmony_ci return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES); 278c2ecf20Sopenharmony_ci} 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* virtio config->finalize_features() implementation */ 308c2ecf20Sopenharmony_cistatic int vp_finalize_features(struct virtio_device *vdev) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* Give virtio_ring a chance to accept features. */ 358c2ecf20Sopenharmony_ci vring_transport_features(vdev); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci /* Make sure we don't have any features > 32 bits! */ 388c2ecf20Sopenharmony_ci BUG_ON((u32)vdev->features != vdev->features); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci /* We only support 32 feature bits. */ 418c2ecf20Sopenharmony_ci iowrite32(vdev->features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci return 0; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* virtio config->get() implementation */ 478c2ecf20Sopenharmony_cistatic void vp_get(struct virtio_device *vdev, unsigned offset, 488c2ecf20Sopenharmony_ci void *buf, unsigned len) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 518c2ecf20Sopenharmony_ci void __iomem *ioaddr = vp_dev->ioaddr + 528c2ecf20Sopenharmony_ci VIRTIO_PCI_CONFIG_OFF(vp_dev->msix_enabled) + 538c2ecf20Sopenharmony_ci offset; 548c2ecf20Sopenharmony_ci u8 *ptr = buf; 558c2ecf20Sopenharmony_ci int i; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 588c2ecf20Sopenharmony_ci ptr[i] = ioread8(ioaddr + i); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/* the config->set() implementation. it's symmetric to the config->get() 628c2ecf20Sopenharmony_ci * implementation */ 638c2ecf20Sopenharmony_cistatic void vp_set(struct virtio_device *vdev, unsigned offset, 648c2ecf20Sopenharmony_ci const void *buf, unsigned len) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 678c2ecf20Sopenharmony_ci void __iomem *ioaddr = vp_dev->ioaddr + 688c2ecf20Sopenharmony_ci VIRTIO_PCI_CONFIG_OFF(vp_dev->msix_enabled) + 698c2ecf20Sopenharmony_ci offset; 708c2ecf20Sopenharmony_ci const u8 *ptr = buf; 718c2ecf20Sopenharmony_ci int i; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 748c2ecf20Sopenharmony_ci iowrite8(ptr[i], ioaddr + i); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* config->{get,set}_status() implementations */ 788c2ecf20Sopenharmony_cistatic u8 vp_get_status(struct virtio_device *vdev) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 818c2ecf20Sopenharmony_ci return ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic void vp_set_status(struct virtio_device *vdev, u8 status) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 878c2ecf20Sopenharmony_ci /* We should never be setting status to 0. */ 888c2ecf20Sopenharmony_ci BUG_ON(status == 0); 898c2ecf20Sopenharmony_ci iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic void vp_reset(struct virtio_device *vdev) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 958c2ecf20Sopenharmony_ci /* 0 status means a reset. */ 968c2ecf20Sopenharmony_ci iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS); 978c2ecf20Sopenharmony_ci /* Flush out the status write, and flush in device writes, 988c2ecf20Sopenharmony_ci * including MSi-X interrupts, if any. */ 998c2ecf20Sopenharmony_ci ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS); 1008c2ecf20Sopenharmony_ci /* Flush pending VQ/configuration callbacks. */ 1018c2ecf20Sopenharmony_ci vp_synchronize_vectors(vdev); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci /* Setup the vector used for configuration events */ 1078c2ecf20Sopenharmony_ci iowrite16(vector, vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR); 1088c2ecf20Sopenharmony_ci /* Verify we had enough resources to assign the vector */ 1098c2ecf20Sopenharmony_ci /* Will also flush the write out to device */ 1108c2ecf20Sopenharmony_ci return ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR); 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, 1148c2ecf20Sopenharmony_ci struct virtio_pci_vq_info *info, 1158c2ecf20Sopenharmony_ci unsigned index, 1168c2ecf20Sopenharmony_ci void (*callback)(struct virtqueue *vq), 1178c2ecf20Sopenharmony_ci const char *name, 1188c2ecf20Sopenharmony_ci bool ctx, 1198c2ecf20Sopenharmony_ci u16 msix_vec) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct virtqueue *vq; 1228c2ecf20Sopenharmony_ci u16 num; 1238c2ecf20Sopenharmony_ci int err; 1248c2ecf20Sopenharmony_ci u64 q_pfn; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci /* Select the queue we're interested in */ 1278c2ecf20Sopenharmony_ci iowrite16(index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* Check if queue is either not available or already active. */ 1308c2ecf20Sopenharmony_ci num = ioread16(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NUM); 1318c2ecf20Sopenharmony_ci if (!num || ioread32(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN)) 1328c2ecf20Sopenharmony_ci return ERR_PTR(-ENOENT); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci info->msix_vector = msix_vec; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* create the vring */ 1378c2ecf20Sopenharmony_ci vq = vring_create_virtqueue(index, num, 1388c2ecf20Sopenharmony_ci VIRTIO_PCI_VRING_ALIGN, &vp_dev->vdev, 1398c2ecf20Sopenharmony_ci true, false, ctx, 1408c2ecf20Sopenharmony_ci vp_notify, callback, name); 1418c2ecf20Sopenharmony_ci if (!vq) 1428c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci q_pfn = virtqueue_get_desc_addr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; 1458c2ecf20Sopenharmony_ci if (q_pfn >> 32) { 1468c2ecf20Sopenharmony_ci dev_err(&vp_dev->pci_dev->dev, 1478c2ecf20Sopenharmony_ci "platform bug: legacy virtio-mmio must not be used with RAM above 0x%llxGB\n", 1488c2ecf20Sopenharmony_ci 0x1ULL << (32 + PAGE_SHIFT - 30)); 1498c2ecf20Sopenharmony_ci err = -E2BIG; 1508c2ecf20Sopenharmony_ci goto out_del_vq; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* activate the queue */ 1548c2ecf20Sopenharmony_ci iowrite32(q_pfn, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci vq->priv = (void __force *)vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (msix_vec != VIRTIO_MSI_NO_VECTOR) { 1598c2ecf20Sopenharmony_ci iowrite16(msix_vec, vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR); 1608c2ecf20Sopenharmony_ci msix_vec = ioread16(vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR); 1618c2ecf20Sopenharmony_ci if (msix_vec == VIRTIO_MSI_NO_VECTOR) { 1628c2ecf20Sopenharmony_ci err = -EBUSY; 1638c2ecf20Sopenharmony_ci goto out_deactivate; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return vq; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ciout_deactivate: 1708c2ecf20Sopenharmony_ci iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); 1718c2ecf20Sopenharmony_ciout_del_vq: 1728c2ecf20Sopenharmony_ci vring_del_virtqueue(vq); 1738c2ecf20Sopenharmony_ci return ERR_PTR(err); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void del_vq(struct virtio_pci_vq_info *info) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct virtqueue *vq = info->vq; 1798c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci iowrite16(vq->index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci if (vp_dev->msix_enabled) { 1848c2ecf20Sopenharmony_ci iowrite16(VIRTIO_MSI_NO_VECTOR, 1858c2ecf20Sopenharmony_ci vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR); 1868c2ecf20Sopenharmony_ci /* Flush the write out to device */ 1878c2ecf20Sopenharmony_ci ioread8(vp_dev->ioaddr + VIRTIO_PCI_ISR); 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Select and deactivate the queue */ 1918c2ecf20Sopenharmony_ci iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci vring_del_virtqueue(vq); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic const struct virtio_config_ops virtio_pci_config_ops = { 1978c2ecf20Sopenharmony_ci .get = vp_get, 1988c2ecf20Sopenharmony_ci .set = vp_set, 1998c2ecf20Sopenharmony_ci .get_status = vp_get_status, 2008c2ecf20Sopenharmony_ci .set_status = vp_set_status, 2018c2ecf20Sopenharmony_ci .reset = vp_reset, 2028c2ecf20Sopenharmony_ci .find_vqs = vp_find_vqs, 2038c2ecf20Sopenharmony_ci .del_vqs = vp_del_vqs, 2048c2ecf20Sopenharmony_ci .get_features = vp_get_features, 2058c2ecf20Sopenharmony_ci .finalize_features = vp_finalize_features, 2068c2ecf20Sopenharmony_ci .bus_name = vp_bus_name, 2078c2ecf20Sopenharmony_ci .set_vq_affinity = vp_set_vq_affinity, 2088c2ecf20Sopenharmony_ci .get_vq_affinity = vp_get_vq_affinity, 2098c2ecf20Sopenharmony_ci}; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* the PCI probing function */ 2128c2ecf20Sopenharmony_ciint virtio_pci_legacy_probe(struct virtio_pci_device *vp_dev) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct pci_dev *pci_dev = vp_dev->pci_dev; 2158c2ecf20Sopenharmony_ci int rc; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* We only own devices >= 0x1000 and <= 0x103f: leave the rest. */ 2188c2ecf20Sopenharmony_ci if (pci_dev->device < 0x1000 || pci_dev->device > 0x103f) 2198c2ecf20Sopenharmony_ci return -ENODEV; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (pci_dev->revision != VIRTIO_PCI_ABI_VERSION) { 2228c2ecf20Sopenharmony_ci printk(KERN_ERR "virtio_pci: expected ABI version %d, got %d\n", 2238c2ecf20Sopenharmony_ci VIRTIO_PCI_ABI_VERSION, pci_dev->revision); 2248c2ecf20Sopenharmony_ci return -ENODEV; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci rc = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(64)); 2288c2ecf20Sopenharmony_ci if (rc) { 2298c2ecf20Sopenharmony_ci rc = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32)); 2308c2ecf20Sopenharmony_ci } else { 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * The virtio ring base address is expressed as a 32-bit PFN, 2338c2ecf20Sopenharmony_ci * with a page size of 1 << VIRTIO_PCI_QUEUE_ADDR_SHIFT. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci dma_set_coherent_mask(&pci_dev->dev, 2368c2ecf20Sopenharmony_ci DMA_BIT_MASK(32 + VIRTIO_PCI_QUEUE_ADDR_SHIFT)); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (rc) 2408c2ecf20Sopenharmony_ci dev_warn(&pci_dev->dev, "Failed to enable 64-bit or 32-bit DMA. Trying to continue, but this might not work.\n"); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci rc = pci_request_region(pci_dev, 0, "virtio-pci-legacy"); 2438c2ecf20Sopenharmony_ci if (rc) 2448c2ecf20Sopenharmony_ci return rc; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci rc = -ENOMEM; 2478c2ecf20Sopenharmony_ci vp_dev->ioaddr = pci_iomap(pci_dev, 0, 0); 2488c2ecf20Sopenharmony_ci if (!vp_dev->ioaddr) 2498c2ecf20Sopenharmony_ci goto err_iomap; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci vp_dev->isr = vp_dev->ioaddr + VIRTIO_PCI_ISR; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* we use the subsystem vendor/device id as the virtio vendor/device 2548c2ecf20Sopenharmony_ci * id. this allows us to use the same PCI vendor/device id for all 2558c2ecf20Sopenharmony_ci * virtio devices and to identify the particular virtio driver by 2568c2ecf20Sopenharmony_ci * the subsystem ids */ 2578c2ecf20Sopenharmony_ci vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor; 2588c2ecf20Sopenharmony_ci vp_dev->vdev.id.device = pci_dev->subsystem_device; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci vp_dev->vdev.config = &virtio_pci_config_ops; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci vp_dev->config_vector = vp_config_vector; 2638c2ecf20Sopenharmony_ci vp_dev->setup_vq = setup_vq; 2648c2ecf20Sopenharmony_ci vp_dev->del_vq = del_vq; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return 0; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cierr_iomap: 2698c2ecf20Sopenharmony_ci pci_release_region(pci_dev, 0); 2708c2ecf20Sopenharmony_ci return rc; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_civoid virtio_pci_legacy_remove(struct virtio_pci_device *vp_dev) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct pci_dev *pci_dev = vp_dev->pci_dev; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci pci_iounmap(pci_dev, vp_dev->ioaddr); 2788c2ecf20Sopenharmony_ci pci_release_region(pci_dev, 0); 2798c2ecf20Sopenharmony_ci} 280