18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Virtio PCI driver - common functionality for all device versions 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_cistatic bool force_legacy = false; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_VIRTIO_PCI_LEGACY) 228c2ecf20Sopenharmony_cimodule_param(force_legacy, bool, 0444); 238c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_legacy, 248c2ecf20Sopenharmony_ci "Force legacy mode for transitional virtio 1 devices"); 258c2ecf20Sopenharmony_ci#endif 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* wait for pending irq handlers */ 288c2ecf20Sopenharmony_civoid vp_synchronize_vectors(struct virtio_device *vdev) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 318c2ecf20Sopenharmony_ci int i; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (vp_dev->intx_enabled) 348c2ecf20Sopenharmony_ci synchronize_irq(vp_dev->pci_dev->irq); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci for (i = 0; i < vp_dev->msix_vectors; ++i) 378c2ecf20Sopenharmony_ci synchronize_irq(pci_irq_vector(vp_dev->pci_dev, i)); 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* the notify function used when creating a virt queue */ 418c2ecf20Sopenharmony_cibool vp_notify(struct virtqueue *vq) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci /* we write the queue's selector into the notification register to 448c2ecf20Sopenharmony_ci * signal the other end */ 458c2ecf20Sopenharmony_ci iowrite16(vq->index, (void __iomem *)vq->priv); 468c2ecf20Sopenharmony_ci return true; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* Handle a configuration change: Tell driver if it wants to know. */ 508c2ecf20Sopenharmony_cistatic irqreturn_t vp_config_changed(int irq, void *opaque) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = opaque; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci virtio_config_changed(&vp_dev->vdev); 558c2ecf20Sopenharmony_ci return IRQ_HANDLED; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* Notify all virtqueues on an interrupt. */ 598c2ecf20Sopenharmony_cistatic irqreturn_t vp_vring_interrupt(int irq, void *opaque) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = opaque; 628c2ecf20Sopenharmony_ci struct virtio_pci_vq_info *info; 638c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 648c2ecf20Sopenharmony_ci unsigned long flags; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci spin_lock_irqsave(&vp_dev->lock, flags); 678c2ecf20Sopenharmony_ci list_for_each_entry(info, &vp_dev->virtqueues, node) { 688c2ecf20Sopenharmony_ci if (vring_interrupt(irq, info->vq) == IRQ_HANDLED) 698c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vp_dev->lock, flags); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return ret; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* A small wrapper to also acknowledge the interrupt when it's handled. 778c2ecf20Sopenharmony_ci * I really need an EIO hook for the vring so I can ack the interrupt once we 788c2ecf20Sopenharmony_ci * know that we'll be handling the IRQ but before we invoke the callback since 798c2ecf20Sopenharmony_ci * the callback may notify the host which results in the host attempting to 808c2ecf20Sopenharmony_ci * raise an interrupt that we would then mask once we acknowledged the 818c2ecf20Sopenharmony_ci * interrupt. */ 828c2ecf20Sopenharmony_cistatic irqreturn_t vp_interrupt(int irq, void *opaque) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = opaque; 858c2ecf20Sopenharmony_ci u8 isr; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* reading the ISR has the effect of also clearing it so it's very 888c2ecf20Sopenharmony_ci * important to save off the value. */ 898c2ecf20Sopenharmony_ci isr = ioread8(vp_dev->isr); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci /* It's definitely not us if the ISR was not high */ 928c2ecf20Sopenharmony_ci if (!isr) 938c2ecf20Sopenharmony_ci return IRQ_NONE; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* Configuration change? Tell driver if it wants to know. */ 968c2ecf20Sopenharmony_ci if (isr & VIRTIO_PCI_ISR_CONFIG) 978c2ecf20Sopenharmony_ci vp_config_changed(irq, opaque); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return vp_vring_interrupt(irq, opaque); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, 1038c2ecf20Sopenharmony_ci bool per_vq_vectors, struct irq_affinity *desc) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 1068c2ecf20Sopenharmony_ci const char *name = dev_name(&vp_dev->vdev.dev); 1078c2ecf20Sopenharmony_ci unsigned flags = PCI_IRQ_MSIX; 1088c2ecf20Sopenharmony_ci unsigned i, v; 1098c2ecf20Sopenharmony_ci int err = -ENOMEM; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci vp_dev->msix_vectors = nvectors; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci vp_dev->msix_names = kmalloc_array(nvectors, 1148c2ecf20Sopenharmony_ci sizeof(*vp_dev->msix_names), 1158c2ecf20Sopenharmony_ci GFP_KERNEL); 1168c2ecf20Sopenharmony_ci if (!vp_dev->msix_names) 1178c2ecf20Sopenharmony_ci goto error; 1188c2ecf20Sopenharmony_ci vp_dev->msix_affinity_masks 1198c2ecf20Sopenharmony_ci = kcalloc(nvectors, sizeof(*vp_dev->msix_affinity_masks), 1208c2ecf20Sopenharmony_ci GFP_KERNEL); 1218c2ecf20Sopenharmony_ci if (!vp_dev->msix_affinity_masks) 1228c2ecf20Sopenharmony_ci goto error; 1238c2ecf20Sopenharmony_ci for (i = 0; i < nvectors; ++i) 1248c2ecf20Sopenharmony_ci if (!alloc_cpumask_var(&vp_dev->msix_affinity_masks[i], 1258c2ecf20Sopenharmony_ci GFP_KERNEL)) 1268c2ecf20Sopenharmony_ci goto error; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (desc) { 1298c2ecf20Sopenharmony_ci flags |= PCI_IRQ_AFFINITY; 1308c2ecf20Sopenharmony_ci desc->pre_vectors++; /* virtio config vector */ 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci err = pci_alloc_irq_vectors_affinity(vp_dev->pci_dev, nvectors, 1348c2ecf20Sopenharmony_ci nvectors, flags, desc); 1358c2ecf20Sopenharmony_ci if (err < 0) 1368c2ecf20Sopenharmony_ci goto error; 1378c2ecf20Sopenharmony_ci vp_dev->msix_enabled = 1; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* Set the vector used for configuration */ 1408c2ecf20Sopenharmony_ci v = vp_dev->msix_used_vectors; 1418c2ecf20Sopenharmony_ci snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names, 1428c2ecf20Sopenharmony_ci "%s-config", name); 1438c2ecf20Sopenharmony_ci err = request_irq(pci_irq_vector(vp_dev->pci_dev, v), 1448c2ecf20Sopenharmony_ci vp_config_changed, 0, vp_dev->msix_names[v], 1458c2ecf20Sopenharmony_ci vp_dev); 1468c2ecf20Sopenharmony_ci if (err) 1478c2ecf20Sopenharmony_ci goto error; 1488c2ecf20Sopenharmony_ci ++vp_dev->msix_used_vectors; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci v = vp_dev->config_vector(vp_dev, v); 1518c2ecf20Sopenharmony_ci /* Verify we had enough resources to assign the vector */ 1528c2ecf20Sopenharmony_ci if (v == VIRTIO_MSI_NO_VECTOR) { 1538c2ecf20Sopenharmony_ci err = -EBUSY; 1548c2ecf20Sopenharmony_ci goto error; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (!per_vq_vectors) { 1588c2ecf20Sopenharmony_ci /* Shared vector for all VQs */ 1598c2ecf20Sopenharmony_ci v = vp_dev->msix_used_vectors; 1608c2ecf20Sopenharmony_ci snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names, 1618c2ecf20Sopenharmony_ci "%s-virtqueues", name); 1628c2ecf20Sopenharmony_ci err = request_irq(pci_irq_vector(vp_dev->pci_dev, v), 1638c2ecf20Sopenharmony_ci vp_vring_interrupt, 0, vp_dev->msix_names[v], 1648c2ecf20Sopenharmony_ci vp_dev); 1658c2ecf20Sopenharmony_ci if (err) 1668c2ecf20Sopenharmony_ci goto error; 1678c2ecf20Sopenharmony_ci ++vp_dev->msix_used_vectors; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_cierror: 1718c2ecf20Sopenharmony_ci return err; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned index, 1758c2ecf20Sopenharmony_ci void (*callback)(struct virtqueue *vq), 1768c2ecf20Sopenharmony_ci const char *name, 1778c2ecf20Sopenharmony_ci bool ctx, 1788c2ecf20Sopenharmony_ci u16 msix_vec) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 1818c2ecf20Sopenharmony_ci struct virtio_pci_vq_info *info = kmalloc(sizeof *info, GFP_KERNEL); 1828c2ecf20Sopenharmony_ci struct virtqueue *vq; 1838c2ecf20Sopenharmony_ci unsigned long flags; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci /* fill out our structure that represents an active queue */ 1868c2ecf20Sopenharmony_ci if (!info) 1878c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci vq = vp_dev->setup_vq(vp_dev, info, index, callback, name, ctx, 1908c2ecf20Sopenharmony_ci msix_vec); 1918c2ecf20Sopenharmony_ci if (IS_ERR(vq)) 1928c2ecf20Sopenharmony_ci goto out_info; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci info->vq = vq; 1958c2ecf20Sopenharmony_ci if (callback) { 1968c2ecf20Sopenharmony_ci spin_lock_irqsave(&vp_dev->lock, flags); 1978c2ecf20Sopenharmony_ci list_add(&info->node, &vp_dev->virtqueues); 1988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vp_dev->lock, flags); 1998c2ecf20Sopenharmony_ci } else { 2008c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&info->node); 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci vp_dev->vqs[index] = info; 2048c2ecf20Sopenharmony_ci return vq; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ciout_info: 2078c2ecf20Sopenharmony_ci kfree(info); 2088c2ecf20Sopenharmony_ci return vq; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void vp_del_vq(struct virtqueue *vq) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev); 2148c2ecf20Sopenharmony_ci struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index]; 2158c2ecf20Sopenharmony_ci unsigned long flags; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci spin_lock_irqsave(&vp_dev->lock, flags); 2188c2ecf20Sopenharmony_ci list_del(&info->node); 2198c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&vp_dev->lock, flags); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci vp_dev->del_vq(info); 2228c2ecf20Sopenharmony_ci kfree(info); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/* the config->del_vqs() implementation */ 2268c2ecf20Sopenharmony_civoid vp_del_vqs(struct virtio_device *vdev) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 2298c2ecf20Sopenharmony_ci struct virtqueue *vq, *n; 2308c2ecf20Sopenharmony_ci int i; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci list_for_each_entry_safe(vq, n, &vdev->vqs, list) { 2338c2ecf20Sopenharmony_ci if (vp_dev->per_vq_vectors) { 2348c2ecf20Sopenharmony_ci int v = vp_dev->vqs[vq->index]->msix_vector; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (v != VIRTIO_MSI_NO_VECTOR) { 2378c2ecf20Sopenharmony_ci int irq = pci_irq_vector(vp_dev->pci_dev, v); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci irq_set_affinity_hint(irq, NULL); 2408c2ecf20Sopenharmony_ci free_irq(irq, vq); 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci vp_del_vq(vq); 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci vp_dev->per_vq_vectors = false; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (vp_dev->intx_enabled) { 2488c2ecf20Sopenharmony_ci free_irq(vp_dev->pci_dev->irq, vp_dev); 2498c2ecf20Sopenharmony_ci vp_dev->intx_enabled = 0; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci for (i = 0; i < vp_dev->msix_used_vectors; ++i) 2538c2ecf20Sopenharmony_ci free_irq(pci_irq_vector(vp_dev->pci_dev, i), vp_dev); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (vp_dev->msix_affinity_masks) { 2568c2ecf20Sopenharmony_ci for (i = 0; i < vp_dev->msix_vectors; i++) 2578c2ecf20Sopenharmony_ci free_cpumask_var(vp_dev->msix_affinity_masks[i]); 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (vp_dev->msix_enabled) { 2618c2ecf20Sopenharmony_ci /* Disable the vector used for configuration */ 2628c2ecf20Sopenharmony_ci vp_dev->config_vector(vp_dev, VIRTIO_MSI_NO_VECTOR); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci pci_free_irq_vectors(vp_dev->pci_dev); 2658c2ecf20Sopenharmony_ci vp_dev->msix_enabled = 0; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci vp_dev->msix_vectors = 0; 2698c2ecf20Sopenharmony_ci vp_dev->msix_used_vectors = 0; 2708c2ecf20Sopenharmony_ci kfree(vp_dev->msix_names); 2718c2ecf20Sopenharmony_ci vp_dev->msix_names = NULL; 2728c2ecf20Sopenharmony_ci kfree(vp_dev->msix_affinity_masks); 2738c2ecf20Sopenharmony_ci vp_dev->msix_affinity_masks = NULL; 2748c2ecf20Sopenharmony_ci kfree(vp_dev->vqs); 2758c2ecf20Sopenharmony_ci vp_dev->vqs = NULL; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs, 2798c2ecf20Sopenharmony_ci struct virtqueue *vqs[], vq_callback_t *callbacks[], 2808c2ecf20Sopenharmony_ci const char * const names[], bool per_vq_vectors, 2818c2ecf20Sopenharmony_ci const bool *ctx, 2828c2ecf20Sopenharmony_ci struct irq_affinity *desc) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 2858c2ecf20Sopenharmony_ci u16 msix_vec; 2868c2ecf20Sopenharmony_ci int i, err, nvectors, allocated_vectors, queue_idx = 0; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL); 2898c2ecf20Sopenharmony_ci if (!vp_dev->vqs) 2908c2ecf20Sopenharmony_ci return -ENOMEM; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (per_vq_vectors) { 2938c2ecf20Sopenharmony_ci /* Best option: one for change interrupt, one per vq. */ 2948c2ecf20Sopenharmony_ci nvectors = 1; 2958c2ecf20Sopenharmony_ci for (i = 0; i < nvqs; ++i) 2968c2ecf20Sopenharmony_ci if (names[i] && callbacks[i]) 2978c2ecf20Sopenharmony_ci ++nvectors; 2988c2ecf20Sopenharmony_ci } else { 2998c2ecf20Sopenharmony_ci /* Second best: one for change, shared for all vqs. */ 3008c2ecf20Sopenharmony_ci nvectors = 2; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci err = vp_request_msix_vectors(vdev, nvectors, per_vq_vectors, 3048c2ecf20Sopenharmony_ci per_vq_vectors ? desc : NULL); 3058c2ecf20Sopenharmony_ci if (err) 3068c2ecf20Sopenharmony_ci goto error_find; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci vp_dev->per_vq_vectors = per_vq_vectors; 3098c2ecf20Sopenharmony_ci allocated_vectors = vp_dev->msix_used_vectors; 3108c2ecf20Sopenharmony_ci for (i = 0; i < nvqs; ++i) { 3118c2ecf20Sopenharmony_ci if (!names[i]) { 3128c2ecf20Sopenharmony_ci vqs[i] = NULL; 3138c2ecf20Sopenharmony_ci continue; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (!callbacks[i]) 3178c2ecf20Sopenharmony_ci msix_vec = VIRTIO_MSI_NO_VECTOR; 3188c2ecf20Sopenharmony_ci else if (vp_dev->per_vq_vectors) 3198c2ecf20Sopenharmony_ci msix_vec = allocated_vectors++; 3208c2ecf20Sopenharmony_ci else 3218c2ecf20Sopenharmony_ci msix_vec = VP_MSIX_VQ_VECTOR; 3228c2ecf20Sopenharmony_ci vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i], 3238c2ecf20Sopenharmony_ci ctx ? ctx[i] : false, 3248c2ecf20Sopenharmony_ci msix_vec); 3258c2ecf20Sopenharmony_ci if (IS_ERR(vqs[i])) { 3268c2ecf20Sopenharmony_ci err = PTR_ERR(vqs[i]); 3278c2ecf20Sopenharmony_ci goto error_find; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (!vp_dev->per_vq_vectors || msix_vec == VIRTIO_MSI_NO_VECTOR) 3318c2ecf20Sopenharmony_ci continue; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* allocate per-vq irq if available and necessary */ 3348c2ecf20Sopenharmony_ci snprintf(vp_dev->msix_names[msix_vec], 3358c2ecf20Sopenharmony_ci sizeof *vp_dev->msix_names, 3368c2ecf20Sopenharmony_ci "%s-%s", 3378c2ecf20Sopenharmony_ci dev_name(&vp_dev->vdev.dev), names[i]); 3388c2ecf20Sopenharmony_ci err = request_irq(pci_irq_vector(vp_dev->pci_dev, msix_vec), 3398c2ecf20Sopenharmony_ci vring_interrupt, 0, 3408c2ecf20Sopenharmony_ci vp_dev->msix_names[msix_vec], 3418c2ecf20Sopenharmony_ci vqs[i]); 3428c2ecf20Sopenharmony_ci if (err) 3438c2ecf20Sopenharmony_ci goto error_find; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cierror_find: 3488c2ecf20Sopenharmony_ci vp_del_vqs(vdev); 3498c2ecf20Sopenharmony_ci return err; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs, 3538c2ecf20Sopenharmony_ci struct virtqueue *vqs[], vq_callback_t *callbacks[], 3548c2ecf20Sopenharmony_ci const char * const names[], const bool *ctx) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 3578c2ecf20Sopenharmony_ci int i, err, queue_idx = 0; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL); 3608c2ecf20Sopenharmony_ci if (!vp_dev->vqs) 3618c2ecf20Sopenharmony_ci return -ENOMEM; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED, 3648c2ecf20Sopenharmony_ci dev_name(&vdev->dev), vp_dev); 3658c2ecf20Sopenharmony_ci if (err) 3668c2ecf20Sopenharmony_ci goto out_del_vqs; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci vp_dev->intx_enabled = 1; 3698c2ecf20Sopenharmony_ci vp_dev->per_vq_vectors = false; 3708c2ecf20Sopenharmony_ci for (i = 0; i < nvqs; ++i) { 3718c2ecf20Sopenharmony_ci if (!names[i]) { 3728c2ecf20Sopenharmony_ci vqs[i] = NULL; 3738c2ecf20Sopenharmony_ci continue; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i], 3768c2ecf20Sopenharmony_ci ctx ? ctx[i] : false, 3778c2ecf20Sopenharmony_ci VIRTIO_MSI_NO_VECTOR); 3788c2ecf20Sopenharmony_ci if (IS_ERR(vqs[i])) { 3798c2ecf20Sopenharmony_ci err = PTR_ERR(vqs[i]); 3808c2ecf20Sopenharmony_ci goto out_del_vqs; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ciout_del_vqs: 3868c2ecf20Sopenharmony_ci vp_del_vqs(vdev); 3878c2ecf20Sopenharmony_ci return err; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci/* the config->find_vqs() implementation */ 3918c2ecf20Sopenharmony_ciint vp_find_vqs(struct virtio_device *vdev, unsigned nvqs, 3928c2ecf20Sopenharmony_ci struct virtqueue *vqs[], vq_callback_t *callbacks[], 3938c2ecf20Sopenharmony_ci const char * const names[], const bool *ctx, 3948c2ecf20Sopenharmony_ci struct irq_affinity *desc) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci int err; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* Try MSI-X with one vector per queue. */ 3998c2ecf20Sopenharmony_ci err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, true, ctx, desc); 4008c2ecf20Sopenharmony_ci if (!err) 4018c2ecf20Sopenharmony_ci return 0; 4028c2ecf20Sopenharmony_ci /* Fallback: MSI-X with one vector for config, one shared for queues. */ 4038c2ecf20Sopenharmony_ci err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, false, ctx, desc); 4048c2ecf20Sopenharmony_ci if (!err) 4058c2ecf20Sopenharmony_ci return 0; 4068c2ecf20Sopenharmony_ci /* Finally fall back to regular interrupts. */ 4078c2ecf20Sopenharmony_ci return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names, ctx); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ciconst char *vp_bus_name(struct virtio_device *vdev) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return pci_name(vp_dev->pci_dev); 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci/* Setup the affinity for a virtqueue: 4188c2ecf20Sopenharmony_ci * - force the affinity for per vq vector 4198c2ecf20Sopenharmony_ci * - OR over all affinities for shared MSI 4208c2ecf20Sopenharmony_ci * - ignore the affinity request if we're using INTX 4218c2ecf20Sopenharmony_ci */ 4228c2ecf20Sopenharmony_ciint vp_set_vq_affinity(struct virtqueue *vq, const struct cpumask *cpu_mask) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct virtio_device *vdev = vq->vdev; 4258c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 4268c2ecf20Sopenharmony_ci struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index]; 4278c2ecf20Sopenharmony_ci struct cpumask *mask; 4288c2ecf20Sopenharmony_ci unsigned int irq; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (!vq->callback) 4318c2ecf20Sopenharmony_ci return -EINVAL; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (vp_dev->msix_enabled) { 4348c2ecf20Sopenharmony_ci mask = vp_dev->msix_affinity_masks[info->msix_vector]; 4358c2ecf20Sopenharmony_ci irq = pci_irq_vector(vp_dev->pci_dev, info->msix_vector); 4368c2ecf20Sopenharmony_ci if (!cpu_mask) 4378c2ecf20Sopenharmony_ci irq_set_affinity_hint(irq, NULL); 4388c2ecf20Sopenharmony_ci else { 4398c2ecf20Sopenharmony_ci cpumask_copy(mask, cpu_mask); 4408c2ecf20Sopenharmony_ci irq_set_affinity_hint(irq, mask); 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ciconst struct cpumask *vp_get_vq_affinity(struct virtio_device *vdev, int index) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (!vp_dev->per_vq_vectors || 4518c2ecf20Sopenharmony_ci vp_dev->vqs[index]->msix_vector == VIRTIO_MSI_NO_VECTOR) 4528c2ecf20Sopenharmony_ci return NULL; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci return pci_irq_get_affinity(vp_dev->pci_dev, 4558c2ecf20Sopenharmony_ci vp_dev->vqs[index]->msix_vector); 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 4598c2ecf20Sopenharmony_cistatic int virtio_pci_freeze(struct device *dev) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct pci_dev *pci_dev = to_pci_dev(dev); 4628c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); 4638c2ecf20Sopenharmony_ci int ret; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci ret = virtio_device_freeze(&vp_dev->vdev); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci if (!ret) 4688c2ecf20Sopenharmony_ci pci_disable_device(pci_dev); 4698c2ecf20Sopenharmony_ci return ret; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic int virtio_pci_restore(struct device *dev) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct pci_dev *pci_dev = to_pci_dev(dev); 4758c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); 4768c2ecf20Sopenharmony_ci int ret; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci ret = pci_enable_device(pci_dev); 4798c2ecf20Sopenharmony_ci if (ret) 4808c2ecf20Sopenharmony_ci return ret; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci pci_set_master(pci_dev); 4838c2ecf20Sopenharmony_ci return virtio_device_restore(&vp_dev->vdev); 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic const struct dev_pm_ops virtio_pci_pm_ops = { 4878c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(virtio_pci_freeze, virtio_pci_restore) 4888c2ecf20Sopenharmony_ci}; 4898c2ecf20Sopenharmony_ci#endif 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci/* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */ 4938c2ecf20Sopenharmony_cistatic const struct pci_device_id virtio_pci_id_table[] = { 4948c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_ANY_ID) }, 4958c2ecf20Sopenharmony_ci { 0 } 4968c2ecf20Sopenharmony_ci}; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, virtio_pci_id_table); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic void virtio_pci_release_dev(struct device *_d) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct virtio_device *vdev = dev_to_virtio(_d); 5038c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = to_vp_device(vdev); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* As struct device is a kobject, it's not safe to 5068c2ecf20Sopenharmony_ci * free the memory (including the reference counter itself) 5078c2ecf20Sopenharmony_ci * until it's release callback. */ 5088c2ecf20Sopenharmony_ci kfree(vp_dev); 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_cistatic int virtio_pci_probe(struct pci_dev *pci_dev, 5128c2ecf20Sopenharmony_ci const struct pci_device_id *id) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev, *reg_dev = NULL; 5158c2ecf20Sopenharmony_ci int rc; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* allocate our structure and fill it out */ 5188c2ecf20Sopenharmony_ci vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL); 5198c2ecf20Sopenharmony_ci if (!vp_dev) 5208c2ecf20Sopenharmony_ci return -ENOMEM; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci pci_set_drvdata(pci_dev, vp_dev); 5238c2ecf20Sopenharmony_ci vp_dev->vdev.dev.parent = &pci_dev->dev; 5248c2ecf20Sopenharmony_ci vp_dev->vdev.dev.release = virtio_pci_release_dev; 5258c2ecf20Sopenharmony_ci vp_dev->pci_dev = pci_dev; 5268c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vp_dev->virtqueues); 5278c2ecf20Sopenharmony_ci spin_lock_init(&vp_dev->lock); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci /* enable the device */ 5308c2ecf20Sopenharmony_ci rc = pci_enable_device(pci_dev); 5318c2ecf20Sopenharmony_ci if (rc) 5328c2ecf20Sopenharmony_ci goto err_enable_device; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci if (force_legacy) { 5358c2ecf20Sopenharmony_ci rc = virtio_pci_legacy_probe(vp_dev); 5368c2ecf20Sopenharmony_ci /* Also try modern mode if we can't map BAR0 (no IO space). */ 5378c2ecf20Sopenharmony_ci if (rc == -ENODEV || rc == -ENOMEM) 5388c2ecf20Sopenharmony_ci rc = virtio_pci_modern_probe(vp_dev); 5398c2ecf20Sopenharmony_ci if (rc) 5408c2ecf20Sopenharmony_ci goto err_probe; 5418c2ecf20Sopenharmony_ci } else { 5428c2ecf20Sopenharmony_ci rc = virtio_pci_modern_probe(vp_dev); 5438c2ecf20Sopenharmony_ci if (rc == -ENODEV) 5448c2ecf20Sopenharmony_ci rc = virtio_pci_legacy_probe(vp_dev); 5458c2ecf20Sopenharmony_ci if (rc) 5468c2ecf20Sopenharmony_ci goto err_probe; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci pci_set_master(pci_dev); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci rc = register_virtio_device(&vp_dev->vdev); 5528c2ecf20Sopenharmony_ci reg_dev = vp_dev; 5538c2ecf20Sopenharmony_ci if (rc) 5548c2ecf20Sopenharmony_ci goto err_register; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci return 0; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_cierr_register: 5598c2ecf20Sopenharmony_ci if (vp_dev->ioaddr) 5608c2ecf20Sopenharmony_ci virtio_pci_legacy_remove(vp_dev); 5618c2ecf20Sopenharmony_ci else 5628c2ecf20Sopenharmony_ci virtio_pci_modern_remove(vp_dev); 5638c2ecf20Sopenharmony_cierr_probe: 5648c2ecf20Sopenharmony_ci pci_disable_device(pci_dev); 5658c2ecf20Sopenharmony_cierr_enable_device: 5668c2ecf20Sopenharmony_ci if (reg_dev) 5678c2ecf20Sopenharmony_ci put_device(&vp_dev->vdev.dev); 5688c2ecf20Sopenharmony_ci else 5698c2ecf20Sopenharmony_ci kfree(vp_dev); 5708c2ecf20Sopenharmony_ci return rc; 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_cistatic void virtio_pci_remove(struct pci_dev *pci_dev) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); 5768c2ecf20Sopenharmony_ci struct device *dev = get_device(&vp_dev->vdev.dev); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* 5798c2ecf20Sopenharmony_ci * Device is marked broken on surprise removal so that virtio upper 5808c2ecf20Sopenharmony_ci * layers can abort any ongoing operation. 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_ci if (!pci_device_is_present(pci_dev)) 5838c2ecf20Sopenharmony_ci virtio_break_device(&vp_dev->vdev); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci pci_disable_sriov(pci_dev); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci unregister_virtio_device(&vp_dev->vdev); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (vp_dev->ioaddr) 5908c2ecf20Sopenharmony_ci virtio_pci_legacy_remove(vp_dev); 5918c2ecf20Sopenharmony_ci else 5928c2ecf20Sopenharmony_ci virtio_pci_modern_remove(vp_dev); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci pci_disable_device(pci_dev); 5958c2ecf20Sopenharmony_ci put_device(dev); 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic int virtio_pci_sriov_configure(struct pci_dev *pci_dev, int num_vfs) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); 6018c2ecf20Sopenharmony_ci struct virtio_device *vdev = &vp_dev->vdev; 6028c2ecf20Sopenharmony_ci int ret; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (!(vdev->config->get_status(vdev) & VIRTIO_CONFIG_S_DRIVER_OK)) 6058c2ecf20Sopenharmony_ci return -EBUSY; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci if (!__virtio_test_bit(vdev, VIRTIO_F_SR_IOV)) 6088c2ecf20Sopenharmony_ci return -EINVAL; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (pci_vfs_assigned(pci_dev)) 6118c2ecf20Sopenharmony_ci return -EPERM; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (num_vfs == 0) { 6148c2ecf20Sopenharmony_ci pci_disable_sriov(pci_dev); 6158c2ecf20Sopenharmony_ci return 0; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci ret = pci_enable_sriov(pci_dev, num_vfs); 6198c2ecf20Sopenharmony_ci if (ret < 0) 6208c2ecf20Sopenharmony_ci return ret; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return num_vfs; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic struct pci_driver virtio_pci_driver = { 6268c2ecf20Sopenharmony_ci .name = "virtio-pci", 6278c2ecf20Sopenharmony_ci .id_table = virtio_pci_id_table, 6288c2ecf20Sopenharmony_ci .probe = virtio_pci_probe, 6298c2ecf20Sopenharmony_ci .remove = virtio_pci_remove, 6308c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 6318c2ecf20Sopenharmony_ci .driver.pm = &virtio_pci_pm_ops, 6328c2ecf20Sopenharmony_ci#endif 6338c2ecf20Sopenharmony_ci .sriov_configure = virtio_pci_sriov_configure, 6348c2ecf20Sopenharmony_ci}; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cimodule_pci_driver(virtio_pci_driver); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ciMODULE_AUTHOR("Anthony Liguori <aliguori@us.ibm.com>"); 6398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("virtio-pci"); 6408c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6418c2ecf20Sopenharmony_ciMODULE_VERSION("1"); 642