1fd502729SJason Wang // SPDX-License-Identifier: GPL-2.0-or-later 2fd502729SJason Wang 3fd502729SJason Wang #include <linux/virtio_pci_modern.h> 4fd502729SJason Wang #include <linux/module.h> 5fd502729SJason Wang #include <linux/pci.h> 6fd502729SJason Wang 7fd502729SJason Wang /* 8fd502729SJason Wang * vp_modern_map_capability - map a part of virtio pci capability 9fd502729SJason Wang * @mdev: the modern virtio-pci device 10fd502729SJason Wang * @off: offset of the capability 11fd502729SJason Wang * @minlen: minimal length of the capability 12fd502729SJason Wang * @align: align requirement 13fd502729SJason Wang * @start: start from the capability 14fd502729SJason Wang * @size: map size 15fd502729SJason Wang * @len: the length that is actually mapped 16fd502729SJason Wang * 17fd502729SJason Wang * Returns the io address of for the part of the capability 18fd502729SJason Wang */ 19*fd466b36SJason Wang static void __iomem * 20*fd466b36SJason Wang vp_modern_map_capability(struct virtio_pci_modern_device *mdev, int off, 21*fd466b36SJason Wang size_t minlen, u32 align, u32 start, u32 size, 22fd502729SJason Wang size_t *len) 23fd502729SJason Wang { 24fd502729SJason Wang struct pci_dev *dev = mdev->pci_dev; 25fd502729SJason Wang u8 bar; 26fd502729SJason Wang u32 offset, length; 27fd502729SJason Wang void __iomem *p; 28fd502729SJason Wang 29fd502729SJason Wang pci_read_config_byte(dev, off + offsetof(struct virtio_pci_cap, 30fd502729SJason Wang bar), 31fd502729SJason Wang &bar); 32fd502729SJason Wang pci_read_config_dword(dev, off + offsetof(struct virtio_pci_cap, offset), 33fd502729SJason Wang &offset); 34fd502729SJason Wang pci_read_config_dword(dev, off + offsetof(struct virtio_pci_cap, length), 35fd502729SJason Wang &length); 36fd502729SJason Wang 37fd502729SJason Wang if (length <= start) { 38fd502729SJason Wang dev_err(&dev->dev, 39fd502729SJason Wang "virtio_pci: bad capability len %u (>%u expected)\n", 40fd502729SJason Wang length, start); 41fd502729SJason Wang return NULL; 42fd502729SJason Wang } 43fd502729SJason Wang 44fd502729SJason Wang if (length - start < minlen) { 45fd502729SJason Wang dev_err(&dev->dev, 46fd502729SJason Wang "virtio_pci: bad capability len %u (>=%zu expected)\n", 47fd502729SJason Wang length, minlen); 48fd502729SJason Wang return NULL; 49fd502729SJason Wang } 50fd502729SJason Wang 51fd502729SJason Wang length -= start; 52fd502729SJason Wang 53fd502729SJason Wang if (start + offset < offset) { 54fd502729SJason Wang dev_err(&dev->dev, 55fd502729SJason Wang "virtio_pci: map wrap-around %u+%u\n", 56fd502729SJason Wang start, offset); 57fd502729SJason Wang return NULL; 58fd502729SJason Wang } 59fd502729SJason Wang 60fd502729SJason Wang offset += start; 61fd502729SJason Wang 62fd502729SJason Wang if (offset & (align - 1)) { 63fd502729SJason Wang dev_err(&dev->dev, 64fd502729SJason Wang "virtio_pci: offset %u not aligned to %u\n", 65fd502729SJason Wang offset, align); 66fd502729SJason Wang return NULL; 67fd502729SJason Wang } 68fd502729SJason Wang 69fd502729SJason Wang if (length > size) 70fd502729SJason Wang length = size; 71fd502729SJason Wang 72fd502729SJason Wang if (len) 73fd502729SJason Wang *len = length; 74fd502729SJason Wang 75fd502729SJason Wang if (minlen + offset < minlen || 76fd502729SJason Wang minlen + offset > pci_resource_len(dev, bar)) { 77fd502729SJason Wang dev_err(&dev->dev, 78fd502729SJason Wang "virtio_pci: map virtio %zu@%u " 79fd502729SJason Wang "out of range on bar %i length %lu\n", 80fd502729SJason Wang minlen, offset, 81fd502729SJason Wang bar, (unsigned long)pci_resource_len(dev, bar)); 82fd502729SJason Wang return NULL; 83fd502729SJason Wang } 84fd502729SJason Wang 85fd502729SJason Wang p = pci_iomap_range(dev, bar, offset, length); 86fd502729SJason Wang if (!p) 87fd502729SJason Wang dev_err(&dev->dev, 88fd502729SJason Wang "virtio_pci: unable to map virtio %u@%u on bar %i\n", 89fd502729SJason Wang length, offset, bar); 90fd502729SJason Wang return p; 91fd502729SJason Wang } 92fd502729SJason Wang 93fd502729SJason Wang /** 94fd502729SJason Wang * virtio_pci_find_capability - walk capabilities to find device info. 95fd502729SJason Wang * @dev: the pci device 96fd502729SJason Wang * @cfg_type: the VIRTIO_PCI_CAP_* value we seek 97fd502729SJason Wang * @ioresource_types: IORESOURCE_MEM and/or IORESOURCE_IO. 98fd502729SJason Wang * @bars: the bitmask of BARs 99fd502729SJason Wang * 100fd502729SJason Wang * Returns offset of the capability, or 0. 101fd502729SJason Wang */ 102fd502729SJason Wang static inline int virtio_pci_find_capability(struct pci_dev *dev, u8 cfg_type, 103fd502729SJason Wang u32 ioresource_types, int *bars) 104fd502729SJason Wang { 105fd502729SJason Wang int pos; 106fd502729SJason Wang 107fd502729SJason Wang for (pos = pci_find_capability(dev, PCI_CAP_ID_VNDR); 108fd502729SJason Wang pos > 0; 109fd502729SJason Wang pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_VNDR)) { 110fd502729SJason Wang u8 type, bar; 111fd502729SJason Wang pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap, 112fd502729SJason Wang cfg_type), 113fd502729SJason Wang &type); 114fd502729SJason Wang pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap, 115fd502729SJason Wang bar), 116fd502729SJason Wang &bar); 117fd502729SJason Wang 118fd502729SJason Wang /* Ignore structures with reserved BAR values */ 119fd502729SJason Wang if (bar > 0x5) 120fd502729SJason Wang continue; 121fd502729SJason Wang 122fd502729SJason Wang if (type == cfg_type) { 123fd502729SJason Wang if (pci_resource_len(dev, bar) && 124fd502729SJason Wang pci_resource_flags(dev, bar) & ioresource_types) { 125fd502729SJason Wang *bars |= (1 << bar); 126fd502729SJason Wang return pos; 127fd502729SJason Wang } 128fd502729SJason Wang } 129fd502729SJason Wang } 130fd502729SJason Wang return 0; 131fd502729SJason Wang } 132fd502729SJason Wang 133fd502729SJason Wang /* This is part of the ABI. Don't screw with it. */ 134fd502729SJason Wang static inline void check_offsets(void) 135fd502729SJason Wang { 136fd502729SJason Wang /* Note: disk space was harmed in compilation of this function. */ 137fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_CAP_VNDR != 138fd502729SJason Wang offsetof(struct virtio_pci_cap, cap_vndr)); 139fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_CAP_NEXT != 140fd502729SJason Wang offsetof(struct virtio_pci_cap, cap_next)); 141fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_CAP_LEN != 142fd502729SJason Wang offsetof(struct virtio_pci_cap, cap_len)); 143fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_CAP_CFG_TYPE != 144fd502729SJason Wang offsetof(struct virtio_pci_cap, cfg_type)); 145fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_CAP_BAR != 146fd502729SJason Wang offsetof(struct virtio_pci_cap, bar)); 147fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_CAP_OFFSET != 148fd502729SJason Wang offsetof(struct virtio_pci_cap, offset)); 149fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_CAP_LENGTH != 150fd502729SJason Wang offsetof(struct virtio_pci_cap, length)); 151fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_NOTIFY_CAP_MULT != 152fd502729SJason Wang offsetof(struct virtio_pci_notify_cap, 153fd502729SJason Wang notify_off_multiplier)); 154fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_DFSELECT != 155fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, 156fd502729SJason Wang device_feature_select)); 157fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_DF != 158fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, device_feature)); 159fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_GFSELECT != 160fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, 161fd502729SJason Wang guest_feature_select)); 162fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_GF != 163fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, guest_feature)); 164fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_MSIX != 165fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, msix_config)); 166fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_NUMQ != 167fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, num_queues)); 168fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_STATUS != 169fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, device_status)); 170fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_CFGGENERATION != 171fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, config_generation)); 172fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_SELECT != 173fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, queue_select)); 174fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_SIZE != 175fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, queue_size)); 176fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_MSIX != 177fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, queue_msix_vector)); 178fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_ENABLE != 179fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, queue_enable)); 180fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_NOFF != 181fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, queue_notify_off)); 182fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_DESCLO != 183fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, queue_desc_lo)); 184fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_DESCHI != 185fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, queue_desc_hi)); 186fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_AVAILLO != 187fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, queue_avail_lo)); 188fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_AVAILHI != 189fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, queue_avail_hi)); 190fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_USEDLO != 191fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, queue_used_lo)); 192fd502729SJason Wang BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_USEDHI != 193fd502729SJason Wang offsetof(struct virtio_pci_common_cfg, queue_used_hi)); 194fd502729SJason Wang } 195fd502729SJason Wang 196fd502729SJason Wang /* 197fd502729SJason Wang * vp_modern_probe: probe the modern virtio pci device, note that the 198fd502729SJason Wang * caller is required to enable PCI device before calling this function. 199fd502729SJason Wang * @mdev: the modern virtio-pci device 200fd502729SJason Wang * 201fd502729SJason Wang * Return 0 on succeed otherwise fail 202fd502729SJason Wang */ 203fd502729SJason Wang int vp_modern_probe(struct virtio_pci_modern_device *mdev) 204fd502729SJason Wang { 205fd502729SJason Wang struct pci_dev *pci_dev = mdev->pci_dev; 206fd502729SJason Wang int err, common, isr, notify, device; 207fd502729SJason Wang u32 notify_length; 208fd502729SJason Wang u32 notify_offset; 209fd502729SJason Wang 210fd502729SJason Wang check_offsets(); 211fd502729SJason Wang 212fd502729SJason Wang mdev->pci_dev = pci_dev; 213fd502729SJason Wang 214fd502729SJason Wang /* We only own devices >= 0x1000 and <= 0x107f: leave the rest. */ 215fd502729SJason Wang if (pci_dev->device < 0x1000 || pci_dev->device > 0x107f) 216fd502729SJason Wang return -ENODEV; 217fd502729SJason Wang 218fd502729SJason Wang if (pci_dev->device < 0x1040) { 219fd502729SJason Wang /* Transitional devices: use the PCI subsystem device id as 220fd502729SJason Wang * virtio device id, same as legacy driver always did. 221fd502729SJason Wang */ 222fd502729SJason Wang mdev->id.device = pci_dev->subsystem_device; 223fd502729SJason Wang } else { 224fd502729SJason Wang /* Modern devices: simply use PCI device id, but start from 0x1040. */ 225fd502729SJason Wang mdev->id.device = pci_dev->device - 0x1040; 226fd502729SJason Wang } 227fd502729SJason Wang mdev->id.vendor = pci_dev->subsystem_vendor; 228fd502729SJason Wang 229fd502729SJason Wang /* check for a common config: if not, use legacy mode (bar 0). */ 230fd502729SJason Wang common = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_COMMON_CFG, 231fd502729SJason Wang IORESOURCE_IO | IORESOURCE_MEM, 232fd502729SJason Wang &mdev->modern_bars); 233fd502729SJason Wang if (!common) { 234fd502729SJason Wang dev_info(&pci_dev->dev, 235fd502729SJason Wang "virtio_pci: leaving for legacy driver\n"); 236fd502729SJason Wang return -ENODEV; 237fd502729SJason Wang } 238fd502729SJason Wang 239fd502729SJason Wang /* If common is there, these should be too... */ 240fd502729SJason Wang isr = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_ISR_CFG, 241fd502729SJason Wang IORESOURCE_IO | IORESOURCE_MEM, 242fd502729SJason Wang &mdev->modern_bars); 243fd502729SJason Wang notify = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_NOTIFY_CFG, 244fd502729SJason Wang IORESOURCE_IO | IORESOURCE_MEM, 245fd502729SJason Wang &mdev->modern_bars); 246fd502729SJason Wang if (!isr || !notify) { 247fd502729SJason Wang dev_err(&pci_dev->dev, 248fd502729SJason Wang "virtio_pci: missing capabilities %i/%i/%i\n", 249fd502729SJason Wang common, isr, notify); 250fd502729SJason Wang return -EINVAL; 251fd502729SJason Wang } 252fd502729SJason Wang 253fd502729SJason Wang err = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(64)); 254fd502729SJason Wang if (err) 255fd502729SJason Wang err = dma_set_mask_and_coherent(&pci_dev->dev, 256fd502729SJason Wang DMA_BIT_MASK(32)); 257fd502729SJason Wang if (err) 258fd502729SJason Wang dev_warn(&pci_dev->dev, "Failed to enable 64-bit or 32-bit DMA. Trying to continue, but this might not work.\n"); 259fd502729SJason Wang 260fd502729SJason Wang /* Device capability is only mandatory for devices that have 261fd502729SJason Wang * device-specific configuration. 262fd502729SJason Wang */ 263fd502729SJason Wang device = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_DEVICE_CFG, 264fd502729SJason Wang IORESOURCE_IO | IORESOURCE_MEM, 265fd502729SJason Wang &mdev->modern_bars); 266fd502729SJason Wang 267fd502729SJason Wang err = pci_request_selected_regions(pci_dev, mdev->modern_bars, 268fd502729SJason Wang "virtio-pci-modern"); 269fd502729SJason Wang if (err) 270fd502729SJason Wang return err; 271fd502729SJason Wang 272fd502729SJason Wang err = -EINVAL; 273fd502729SJason Wang mdev->common = vp_modern_map_capability(mdev, common, 274fd502729SJason Wang sizeof(struct virtio_pci_common_cfg), 4, 275fd502729SJason Wang 0, sizeof(struct virtio_pci_common_cfg), 276fd502729SJason Wang NULL); 277fd502729SJason Wang if (!mdev->common) 278fd502729SJason Wang goto err_map_common; 279fd502729SJason Wang mdev->isr = vp_modern_map_capability(mdev, isr, sizeof(u8), 1, 280fd502729SJason Wang 0, 1, 281fd502729SJason Wang NULL); 282fd502729SJason Wang if (!mdev->isr) 283fd502729SJason Wang goto err_map_isr; 284fd502729SJason Wang 285fd502729SJason Wang /* Read notify_off_multiplier from config space. */ 286fd502729SJason Wang pci_read_config_dword(pci_dev, 287fd502729SJason Wang notify + offsetof(struct virtio_pci_notify_cap, 288fd502729SJason Wang notify_off_multiplier), 289fd502729SJason Wang &mdev->notify_offset_multiplier); 290fd502729SJason Wang /* Read notify length and offset from config space. */ 291fd502729SJason Wang pci_read_config_dword(pci_dev, 292fd502729SJason Wang notify + offsetof(struct virtio_pci_notify_cap, 293fd502729SJason Wang cap.length), 294fd502729SJason Wang ¬ify_length); 295fd502729SJason Wang 296fd502729SJason Wang pci_read_config_dword(pci_dev, 297fd502729SJason Wang notify + offsetof(struct virtio_pci_notify_cap, 298fd502729SJason Wang cap.offset), 299fd502729SJason Wang ¬ify_offset); 300fd502729SJason Wang 301fd502729SJason Wang /* We don't know how many VQs we'll map, ahead of the time. 302fd502729SJason Wang * If notify length is small, map it all now. 303fd502729SJason Wang * Otherwise, map each VQ individually later. 304fd502729SJason Wang */ 305fd502729SJason Wang if ((u64)notify_length + (notify_offset % PAGE_SIZE) <= PAGE_SIZE) { 306fd502729SJason Wang mdev->notify_base = vp_modern_map_capability(mdev, notify, 307fd502729SJason Wang 2, 2, 308fd502729SJason Wang 0, notify_length, 309fd502729SJason Wang &mdev->notify_len); 310fd502729SJason Wang if (!mdev->notify_base) 311fd502729SJason Wang goto err_map_notify; 312fd502729SJason Wang } else { 313fd502729SJason Wang mdev->notify_map_cap = notify; 314fd502729SJason Wang } 315fd502729SJason Wang 316fd502729SJason Wang /* Again, we don't know how much we should map, but PAGE_SIZE 317fd502729SJason Wang * is more than enough for all existing devices. 318fd502729SJason Wang */ 319fd502729SJason Wang if (device) { 320fd502729SJason Wang mdev->device = vp_modern_map_capability(mdev, device, 0, 4, 321fd502729SJason Wang 0, PAGE_SIZE, 322fd502729SJason Wang &mdev->device_len); 323fd502729SJason Wang if (!mdev->device) 324fd502729SJason Wang goto err_map_device; 325fd502729SJason Wang } 326fd502729SJason Wang 327fd502729SJason Wang return 0; 328fd502729SJason Wang 329fd502729SJason Wang err_map_device: 330fd502729SJason Wang if (mdev->notify_base) 331fd502729SJason Wang pci_iounmap(pci_dev, mdev->notify_base); 332fd502729SJason Wang err_map_notify: 333fd502729SJason Wang pci_iounmap(pci_dev, mdev->isr); 334fd502729SJason Wang err_map_isr: 335fd502729SJason Wang pci_iounmap(pci_dev, mdev->common); 336fd502729SJason Wang err_map_common: 337fd502729SJason Wang return err; 338fd502729SJason Wang } 339fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_probe); 340fd502729SJason Wang 341fd502729SJason Wang /* 342fd502729SJason Wang * vp_modern_probe: remove and cleanup the modern virtio pci device 343fd502729SJason Wang * @mdev: the modern virtio-pci device 344fd502729SJason Wang */ 345fd502729SJason Wang void vp_modern_remove(struct virtio_pci_modern_device *mdev) 346fd502729SJason Wang { 347fd502729SJason Wang struct pci_dev *pci_dev = mdev->pci_dev; 348fd502729SJason Wang 349fd502729SJason Wang if (mdev->device) 350fd502729SJason Wang pci_iounmap(pci_dev, mdev->device); 351fd502729SJason Wang if (mdev->notify_base) 352fd502729SJason Wang pci_iounmap(pci_dev, mdev->notify_base); 353fd502729SJason Wang pci_iounmap(pci_dev, mdev->isr); 354fd502729SJason Wang pci_iounmap(pci_dev, mdev->common); 355fd502729SJason Wang pci_release_selected_regions(pci_dev, mdev->modern_bars); 356fd502729SJason Wang } 357fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_remove); 358fd502729SJason Wang 359fd502729SJason Wang /* 360fd502729SJason Wang * vp_modern_get_features - get features from device 361fd502729SJason Wang * @mdev: the modern virtio-pci device 362fd502729SJason Wang * 363fd502729SJason Wang * Returns the features read from the device 364fd502729SJason Wang */ 365fd502729SJason Wang u64 vp_modern_get_features(struct virtio_pci_modern_device *mdev) 366fd502729SJason Wang { 367fd502729SJason Wang struct virtio_pci_common_cfg __iomem *cfg = mdev->common; 368fd502729SJason Wang 369fd502729SJason Wang u64 features; 370fd502729SJason Wang 371fd502729SJason Wang vp_iowrite32(0, &cfg->device_feature_select); 372fd502729SJason Wang features = vp_ioread32(&cfg->device_feature); 373fd502729SJason Wang vp_iowrite32(1, &cfg->device_feature_select); 374fd502729SJason Wang features |= ((u64)vp_ioread32(&cfg->device_feature) << 32); 375fd502729SJason Wang 376fd502729SJason Wang return features; 377fd502729SJason Wang } 378fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_get_features); 379fd502729SJason Wang 380fd502729SJason Wang /* 381fd502729SJason Wang * vp_modern_set_features - set features to device 382fd502729SJason Wang * @mdev: the modern virtio-pci device 383fd502729SJason Wang * @features: the features set to device 384fd502729SJason Wang */ 385fd502729SJason Wang void vp_modern_set_features(struct virtio_pci_modern_device *mdev, 386fd502729SJason Wang u64 features) 387fd502729SJason Wang { 388fd502729SJason Wang struct virtio_pci_common_cfg __iomem *cfg = mdev->common; 389fd502729SJason Wang 390fd502729SJason Wang vp_iowrite32(0, &cfg->guest_feature_select); 391fd502729SJason Wang vp_iowrite32((u32)features, &cfg->guest_feature); 392fd502729SJason Wang vp_iowrite32(1, &cfg->guest_feature_select); 393fd502729SJason Wang vp_iowrite32(features >> 32, &cfg->guest_feature); 394fd502729SJason Wang } 395fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_set_features); 396fd502729SJason Wang 397fd502729SJason Wang /* 398fd502729SJason Wang * vp_modern_generation - get the device genreation 399fd502729SJason Wang * @mdev: the modern virtio-pci device 400fd502729SJason Wang * 401fd502729SJason Wang * Returns the genreation read from device 402fd502729SJason Wang */ 403fd502729SJason Wang u32 vp_modern_generation(struct virtio_pci_modern_device *mdev) 404fd502729SJason Wang { 405fd502729SJason Wang struct virtio_pci_common_cfg __iomem *cfg = mdev->common; 406fd502729SJason Wang 407fd502729SJason Wang return vp_ioread8(&cfg->config_generation); 408fd502729SJason Wang } 409fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_generation); 410fd502729SJason Wang 411fd502729SJason Wang /* 412fd502729SJason Wang * vp_modern_get_status - get the device status 413fd502729SJason Wang * @mdev: the modern virtio-pci device 414fd502729SJason Wang * 415fd502729SJason Wang * Returns the status read from device 416fd502729SJason Wang */ 417fd502729SJason Wang u8 vp_modern_get_status(struct virtio_pci_modern_device *mdev) 418fd502729SJason Wang { 419fd502729SJason Wang struct virtio_pci_common_cfg __iomem *cfg = mdev->common; 420fd502729SJason Wang 421fd502729SJason Wang return vp_ioread8(&cfg->device_status); 422fd502729SJason Wang } 423fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_get_status); 424fd502729SJason Wang 425fd502729SJason Wang /* 426fd502729SJason Wang * vp_modern_set_status - set status to device 427fd502729SJason Wang * @mdev: the modern virtio-pci device 428fd502729SJason Wang * @status: the status set to device 429fd502729SJason Wang */ 430fd502729SJason Wang void vp_modern_set_status(struct virtio_pci_modern_device *mdev, 431fd502729SJason Wang u8 status) 432fd502729SJason Wang { 433fd502729SJason Wang struct virtio_pci_common_cfg __iomem *cfg = mdev->common; 434fd502729SJason Wang 435fd502729SJason Wang vp_iowrite8(status, &cfg->device_status); 436fd502729SJason Wang } 437fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_set_status); 438fd502729SJason Wang 439fd502729SJason Wang /* 440fd502729SJason Wang * vp_modern_queue_vector - set the MSIX vector for a specific virtqueue 441fd502729SJason Wang * @mdev: the modern virtio-pci device 442fd502729SJason Wang * @index: queue index 443fd502729SJason Wang * @vector: the config vector 444fd502729SJason Wang * 445fd502729SJason Wang * Returns the config vector read from the device 446fd502729SJason Wang */ 447fd502729SJason Wang u16 vp_modern_queue_vector(struct virtio_pci_modern_device *mdev, 448fd502729SJason Wang u16 index, u16 vector) 449fd502729SJason Wang { 450fd502729SJason Wang struct virtio_pci_common_cfg __iomem *cfg = mdev->common; 451fd502729SJason Wang 452fd502729SJason Wang vp_iowrite16(index, &cfg->queue_select); 453fd502729SJason Wang vp_iowrite16(vector, &cfg->queue_msix_vector); 454fd502729SJason Wang /* Flush the write out to device */ 455fd502729SJason Wang return vp_ioread16(&cfg->queue_msix_vector); 456fd502729SJason Wang } 457fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_queue_vector); 458fd502729SJason Wang 459fd502729SJason Wang /* 460fd502729SJason Wang * vp_modern_config_vector - set the vector for config interrupt 461fd502729SJason Wang * @mdev: the modern virtio-pci device 462fd502729SJason Wang * @vector: the config vector 463fd502729SJason Wang * 464fd502729SJason Wang * Returns the config vector read from the device 465fd502729SJason Wang */ 466fd502729SJason Wang u16 vp_modern_config_vector(struct virtio_pci_modern_device *mdev, 467fd502729SJason Wang u16 vector) 468fd502729SJason Wang { 469fd502729SJason Wang struct virtio_pci_common_cfg __iomem *cfg = mdev->common; 470fd502729SJason Wang 471fd502729SJason Wang /* Setup the vector used for configuration events */ 472fd502729SJason Wang vp_iowrite16(vector, &cfg->msix_config); 473fd502729SJason Wang /* Verify we had enough resources to assign the vector */ 474fd502729SJason Wang /* Will also flush the write out to device */ 475fd502729SJason Wang return vp_ioread16(&cfg->msix_config); 476fd502729SJason Wang } 477fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_config_vector); 478fd502729SJason Wang 479fd502729SJason Wang /* 480fd502729SJason Wang * vp_modern_queue_address - set the virtqueue address 481fd502729SJason Wang * @mdev: the modern virtio-pci device 482fd502729SJason Wang * @index: the queue index 483fd502729SJason Wang * @desc_addr: address of the descriptor area 484fd502729SJason Wang * @driver_addr: address of the driver area 485fd502729SJason Wang * @device_addr: address of the device area 486fd502729SJason Wang */ 487fd502729SJason Wang void vp_modern_queue_address(struct virtio_pci_modern_device *mdev, 488fd502729SJason Wang u16 index, u64 desc_addr, u64 driver_addr, 489fd502729SJason Wang u64 device_addr) 490fd502729SJason Wang { 491fd502729SJason Wang struct virtio_pci_common_cfg __iomem *cfg = mdev->common; 492fd502729SJason Wang 493fd502729SJason Wang vp_iowrite16(index, &cfg->queue_select); 494fd502729SJason Wang 495fd502729SJason Wang vp_iowrite64_twopart(desc_addr, &cfg->queue_desc_lo, 496fd502729SJason Wang &cfg->queue_desc_hi); 497fd502729SJason Wang vp_iowrite64_twopart(driver_addr, &cfg->queue_avail_lo, 498fd502729SJason Wang &cfg->queue_avail_hi); 499fd502729SJason Wang vp_iowrite64_twopart(device_addr, &cfg->queue_used_lo, 500fd502729SJason Wang &cfg->queue_used_hi); 501fd502729SJason Wang } 502fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_queue_address); 503fd502729SJason Wang 504fd502729SJason Wang /* 505fd502729SJason Wang * vp_modern_set_queue_enable - enable a virtqueue 506fd502729SJason Wang * @mdev: the modern virtio-pci device 507fd502729SJason Wang * @index: the queue index 508fd502729SJason Wang * @enable: whether the virtqueue is enable or not 509fd502729SJason Wang */ 510fd502729SJason Wang void vp_modern_set_queue_enable(struct virtio_pci_modern_device *mdev, 511fd502729SJason Wang u16 index, bool enable) 512fd502729SJason Wang { 513fd502729SJason Wang vp_iowrite16(index, &mdev->common->queue_select); 514fd502729SJason Wang vp_iowrite16(enable, &mdev->common->queue_enable); 515fd502729SJason Wang } 516fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_set_queue_enable); 517fd502729SJason Wang 518fd502729SJason Wang /* 519fd502729SJason Wang * vp_modern_get_queue_enable - enable a virtqueue 520fd502729SJason Wang * @mdev: the modern virtio-pci device 521fd502729SJason Wang * @index: the queue index 522fd502729SJason Wang * 523fd502729SJason Wang * Returns whether a virtqueue is enabled or not 524fd502729SJason Wang */ 525fd502729SJason Wang bool vp_modern_get_queue_enable(struct virtio_pci_modern_device *mdev, 526fd502729SJason Wang u16 index) 527fd502729SJason Wang { 528fd502729SJason Wang vp_iowrite16(index, &mdev->common->queue_select); 529fd502729SJason Wang 530fd502729SJason Wang return vp_ioread16(&mdev->common->queue_enable); 531fd502729SJason Wang } 532fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_get_queue_enable); 533fd502729SJason Wang 534fd502729SJason Wang /* 535fd502729SJason Wang * vp_modern_set_queue_size - set size for a virtqueue 536fd502729SJason Wang * @mdev: the modern virtio-pci device 537fd502729SJason Wang * @index: the queue index 538fd502729SJason Wang * @size: the size of the virtqueue 539fd502729SJason Wang */ 540fd502729SJason Wang void vp_modern_set_queue_size(struct virtio_pci_modern_device *mdev, 541fd502729SJason Wang u16 index, u16 size) 542fd502729SJason Wang { 543fd502729SJason Wang vp_iowrite16(index, &mdev->common->queue_select); 544fd502729SJason Wang vp_iowrite16(size, &mdev->common->queue_size); 545fd502729SJason Wang 546fd502729SJason Wang } 547fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_set_queue_size); 548fd502729SJason Wang 549fd502729SJason Wang /* 550fd502729SJason Wang * vp_modern_get_queue_size - get size for a virtqueue 551fd502729SJason Wang * @mdev: the modern virtio-pci device 552fd502729SJason Wang * @index: the queue index 553fd502729SJason Wang * 554fd502729SJason Wang * Returns the size of the virtqueue 555fd502729SJason Wang */ 556fd502729SJason Wang u16 vp_modern_get_queue_size(struct virtio_pci_modern_device *mdev, 557fd502729SJason Wang u16 index) 558fd502729SJason Wang { 559fd502729SJason Wang vp_iowrite16(index, &mdev->common->queue_select); 560fd502729SJason Wang 561fd502729SJason Wang return vp_ioread16(&mdev->common->queue_size); 562fd502729SJason Wang 563fd502729SJason Wang } 564fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_get_queue_size); 565fd502729SJason Wang 566fd502729SJason Wang /* 567fd502729SJason Wang * vp_modern_get_num_queues - get the number of virtqueues 568fd502729SJason Wang * @mdev: the modern virtio-pci device 569fd502729SJason Wang * 570fd502729SJason Wang * Returns the number of virtqueues 571fd502729SJason Wang */ 572fd502729SJason Wang u16 vp_modern_get_num_queues(struct virtio_pci_modern_device *mdev) 573fd502729SJason Wang { 574fd502729SJason Wang return vp_ioread16(&mdev->common->num_queues); 575fd502729SJason Wang } 576fd502729SJason Wang EXPORT_SYMBOL_GPL(vp_modern_get_num_queues); 577fd502729SJason Wang 578fd502729SJason Wang /* 579fd502729SJason Wang * vp_modern_get_queue_notify_off - get notification offset for a virtqueue 580fd502729SJason Wang * @mdev: the modern virtio-pci device 581fd502729SJason Wang * @index: the queue index 582fd502729SJason Wang * 583fd502729SJason Wang * Returns the notification offset for a virtqueue 584fd502729SJason Wang */ 585a5f7a24fSJason Wang static u16 vp_modern_get_queue_notify_off(struct virtio_pci_modern_device *mdev, 586fd502729SJason Wang u16 index) 587fd502729SJason Wang { 588fd502729SJason Wang vp_iowrite16(index, &mdev->common->queue_select); 589fd502729SJason Wang 590fd502729SJason Wang return vp_ioread16(&mdev->common->queue_notify_off); 591fd502729SJason Wang } 592fd502729SJason Wang 5939e3bb9b7SJason Wang /* 5949e3bb9b7SJason Wang * vp_modern_map_vq_notify - map notification area for a 5959e3bb9b7SJason Wang * specific virtqueue 5969e3bb9b7SJason Wang * @mdev: the modern virtio-pci device 5979e3bb9b7SJason Wang * @index: the queue index 5989e3bb9b7SJason Wang * 5999e3bb9b7SJason Wang * Returns the address of the notification area 6009e3bb9b7SJason Wang */ 6019e3bb9b7SJason Wang void *vp_modern_map_vq_notify(struct virtio_pci_modern_device *mdev, 6029e3bb9b7SJason Wang u16 index) 6039e3bb9b7SJason Wang { 6049e3bb9b7SJason Wang u16 off = vp_modern_get_queue_notify_off(mdev, index); 6059e3bb9b7SJason Wang 6069e3bb9b7SJason Wang if (mdev->notify_base) { 6079e3bb9b7SJason Wang /* offset should not wrap */ 6089e3bb9b7SJason Wang if ((u64)off * mdev->notify_offset_multiplier + 2 6099e3bb9b7SJason Wang > mdev->notify_len) { 6109e3bb9b7SJason Wang dev_warn(&mdev->pci_dev->dev, 6119e3bb9b7SJason Wang "bad notification offset %u (x %u) " 6129e3bb9b7SJason Wang "for queue %u > %zd", 6139e3bb9b7SJason Wang off, mdev->notify_offset_multiplier, 6149e3bb9b7SJason Wang index, mdev->notify_len); 6159e3bb9b7SJason Wang return NULL; 6169e3bb9b7SJason Wang } 6179e3bb9b7SJason Wang return (void __force *)mdev->notify_base + 6189e3bb9b7SJason Wang off * mdev->notify_offset_multiplier; 6199e3bb9b7SJason Wang } else { 6209e3bb9b7SJason Wang return (void __force *)vp_modern_map_capability(mdev, 6219e3bb9b7SJason Wang mdev->notify_map_cap, 2, 2, 6229e3bb9b7SJason Wang off * mdev->notify_offset_multiplier, 2, 6239e3bb9b7SJason Wang NULL); 6249e3bb9b7SJason Wang } 6259e3bb9b7SJason Wang } 6269e3bb9b7SJason Wang EXPORT_SYMBOL_GPL(vp_modern_map_vq_notify); 6279e3bb9b7SJason Wang 628fd502729SJason Wang MODULE_VERSION("0.1"); 629fd502729SJason Wang MODULE_DESCRIPTION("Modern Virtio PCI Device"); 630fd502729SJason Wang MODULE_AUTHOR("Jason Wang <jasowang@redhat.com>"); 631fd502729SJason Wang MODULE_LICENSE("GPL"); 632