223 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2 3#include "linux/virtio_pci.h"4#include <linux/virtio_pci_legacy.h>5#include <linux/module.h>6#include <linux/pci.h>7 8 9/*10 * vp_legacy_probe: probe the legacy virtio pci device, note that the11 * caller is required to enable PCI device before calling this function.12 * @ldev: the legacy virtio-pci device13 *14 * Return 0 on succeed otherwise fail15 */16int vp_legacy_probe(struct virtio_pci_legacy_device *ldev)17{18 struct pci_dev *pci_dev = ldev->pci_dev;19 int rc;20 21 /* We only own devices >= 0x1000 and <= 0x103f: leave the rest. */22 if (pci_dev->device < 0x1000 || pci_dev->device > 0x103f)23 return -ENODEV;24 25 if (pci_dev->revision != VIRTIO_PCI_ABI_VERSION)26 return -ENODEV;27 28 rc = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(64));29 if (rc) {30 rc = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32));31 } else {32 /*33 * The virtio ring base address is expressed as a 32-bit PFN,34 * with a page size of 1 << VIRTIO_PCI_QUEUE_ADDR_SHIFT.35 */36 dma_set_coherent_mask(&pci_dev->dev,37 DMA_BIT_MASK(32 + VIRTIO_PCI_QUEUE_ADDR_SHIFT));38 }39 40 if (rc)41 dev_warn(&pci_dev->dev, "Failed to enable 64-bit or 32-bit DMA. Trying to continue, but this might not work.\n");42 43 rc = pci_request_region(pci_dev, 0, "virtio-pci-legacy");44 if (rc)45 return rc;46 47 ldev->ioaddr = pci_iomap(pci_dev, 0, 0);48 if (!ldev->ioaddr) {49 rc = -EIO;50 goto err_iomap;51 }52 53 ldev->isr = ldev->ioaddr + VIRTIO_PCI_ISR;54 55 ldev->id.vendor = pci_dev->subsystem_vendor;56 ldev->id.device = pci_dev->subsystem_device;57 58 return 0;59err_iomap:60 pci_release_region(pci_dev, 0);61 return rc;62}63EXPORT_SYMBOL_GPL(vp_legacy_probe);64 65/*66 * vp_legacy_probe: remove and cleanup the legacy virtio pci device67 * @ldev: the legacy virtio-pci device68 */69void vp_legacy_remove(struct virtio_pci_legacy_device *ldev)70{71 struct pci_dev *pci_dev = ldev->pci_dev;72 73 pci_iounmap(pci_dev, ldev->ioaddr);74 pci_release_region(pci_dev, 0);75}76EXPORT_SYMBOL_GPL(vp_legacy_remove);77 78/*79 * vp_legacy_get_features - get features from device80 * @ldev: the legacy virtio-pci device81 *82 * Returns the features read from the device83 */84u64 vp_legacy_get_features(struct virtio_pci_legacy_device *ldev)85{86 87 return ioread32(ldev->ioaddr + VIRTIO_PCI_HOST_FEATURES);88}89EXPORT_SYMBOL_GPL(vp_legacy_get_features);90 91/*92 * vp_legacy_get_driver_features - get driver features from device93 * @ldev: the legacy virtio-pci device94 *95 * Returns the driver features read from the device96 */97u64 vp_legacy_get_driver_features(struct virtio_pci_legacy_device *ldev)98{99 return ioread32(ldev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);100}101EXPORT_SYMBOL_GPL(vp_legacy_get_driver_features);102 103/*104 * vp_legacy_set_features - set features to device105 * @ldev: the legacy virtio-pci device106 * @features: the features set to device107 */108void vp_legacy_set_features(struct virtio_pci_legacy_device *ldev,109 u32 features)110{111 iowrite32(features, ldev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);112}113EXPORT_SYMBOL_GPL(vp_legacy_set_features);114 115/*116 * vp_legacy_get_status - get the device status117 * @ldev: the legacy virtio-pci device118 *119 * Returns the status read from device120 */121u8 vp_legacy_get_status(struct virtio_pci_legacy_device *ldev)122{123 return ioread8(ldev->ioaddr + VIRTIO_PCI_STATUS);124}125EXPORT_SYMBOL_GPL(vp_legacy_get_status);126 127/*128 * vp_legacy_set_status - set status to device129 * @ldev: the legacy virtio-pci device130 * @status: the status set to device131 */132void vp_legacy_set_status(struct virtio_pci_legacy_device *ldev,133 u8 status)134{135 iowrite8(status, ldev->ioaddr + VIRTIO_PCI_STATUS);136}137EXPORT_SYMBOL_GPL(vp_legacy_set_status);138 139/*140 * vp_legacy_queue_vector - set the MSIX vector for a specific virtqueue141 * @ldev: the legacy virtio-pci device142 * @index: queue index143 * @vector: the config vector144 *145 * Returns the config vector read from the device146 */147u16 vp_legacy_queue_vector(struct virtio_pci_legacy_device *ldev,148 u16 index, u16 vector)149{150 iowrite16(index, ldev->ioaddr + VIRTIO_PCI_QUEUE_SEL);151 iowrite16(vector, ldev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);152 /* Flush the write out to device */153 return ioread16(ldev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);154}155EXPORT_SYMBOL_GPL(vp_legacy_queue_vector);156 157/*158 * vp_legacy_config_vector - set the vector for config interrupt159 * @ldev: the legacy virtio-pci device160 * @vector: the config vector161 *162 * Returns the config vector read from the device163 */164u16 vp_legacy_config_vector(struct virtio_pci_legacy_device *ldev,165 u16 vector)166{167 /* Setup the vector used for configuration events */168 iowrite16(vector, ldev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);169 /* Verify we had enough resources to assign the vector */170 /* Will also flush the write out to device */171 return ioread16(ldev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);172}173EXPORT_SYMBOL_GPL(vp_legacy_config_vector);174 175/*176 * vp_legacy_set_queue_address - set the virtqueue address177 * @ldev: the legacy virtio-pci device178 * @index: the queue index179 * @queue_pfn: pfn of the virtqueue180 */181void vp_legacy_set_queue_address(struct virtio_pci_legacy_device *ldev,182 u16 index, u32 queue_pfn)183{184 iowrite16(index, ldev->ioaddr + VIRTIO_PCI_QUEUE_SEL);185 iowrite32(queue_pfn, ldev->ioaddr + VIRTIO_PCI_QUEUE_PFN);186}187EXPORT_SYMBOL_GPL(vp_legacy_set_queue_address);188 189/*190 * vp_legacy_get_queue_enable - enable a virtqueue191 * @ldev: the legacy virtio-pci device192 * @index: the queue index193 *194 * Returns whether a virtqueue is enabled or not195 */196bool vp_legacy_get_queue_enable(struct virtio_pci_legacy_device *ldev,197 u16 index)198{199 iowrite16(index, ldev->ioaddr + VIRTIO_PCI_QUEUE_SEL);200 return ioread32(ldev->ioaddr + VIRTIO_PCI_QUEUE_PFN);201}202EXPORT_SYMBOL_GPL(vp_legacy_get_queue_enable);203 204/*205 * vp_legacy_get_queue_size - get size for a virtqueue206 * @ldev: the legacy virtio-pci device207 * @index: the queue index208 *209 * Returns the size of the virtqueue210 */211u16 vp_legacy_get_queue_size(struct virtio_pci_legacy_device *ldev,212 u16 index)213{214 iowrite16(index, ldev->ioaddr + VIRTIO_PCI_QUEUE_SEL);215 return ioread16(ldev->ioaddr + VIRTIO_PCI_QUEUE_NUM);216}217EXPORT_SYMBOL_GPL(vp_legacy_get_queue_size);218 219MODULE_VERSION("0.1");220MODULE_DESCRIPTION("Legacy Virtio PCI Device");221MODULE_AUTHOR("Wu Zongyong <wuzongyong@linux.alibaba.com>");222MODULE_LICENSE("GPL");223