LCOV - code coverage report
Current view: top level - drivers/virtio - virtio_pci_common.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 1 298 0.3 %
Date: 2022-03-28 16:04:14 Functions: 1 22 4.5 %
Branches: 0 164 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-or-later
       2                 :            : /*
       3                 :            :  * Virtio PCI driver - common functionality for all device versions
       4                 :            :  *
       5                 :            :  * This module allows virtio devices to be used over a virtual PCI device.
       6                 :            :  * This can be used with QEMU based VMMs like KVM or Xen.
       7                 :            :  *
       8                 :            :  * Copyright IBM Corp. 2007
       9                 :            :  * Copyright Red Hat, Inc. 2014
      10                 :            :  *
      11                 :            :  * Authors:
      12                 :            :  *  Anthony Liguori  <aliguori@us.ibm.com>
      13                 :            :  *  Rusty Russell <rusty@rustcorp.com.au>
      14                 :            :  *  Michael S. Tsirkin <mst@redhat.com>
      15                 :            :  */
      16                 :            : 
      17                 :            : #include "virtio_pci_common.h"
      18                 :            : 
      19                 :            : static bool force_legacy = false;
      20                 :            : 
      21                 :            : #if IS_ENABLED(CONFIG_VIRTIO_PCI_LEGACY)
      22                 :            : module_param(force_legacy, bool, 0444);
      23                 :            : MODULE_PARM_DESC(force_legacy,
      24                 :            :                  "Force legacy mode for transitional virtio 1 devices");
      25                 :            : #endif
      26                 :            : 
      27                 :            : /* wait for pending irq handlers */
      28                 :          0 : void vp_synchronize_vectors(struct virtio_device *vdev)
      29                 :            : {
      30         [ #  # ]:          0 :         struct virtio_pci_device *vp_dev = to_vp_device(vdev);
      31                 :          0 :         int i;
      32                 :            : 
      33         [ #  # ]:          0 :         if (vp_dev->intx_enabled)
      34                 :          0 :                 synchronize_irq(vp_dev->pci_dev->irq);
      35                 :            : 
      36         [ #  # ]:          0 :         for (i = 0; i < vp_dev->msix_vectors; ++i)
      37                 :          0 :                 synchronize_irq(pci_irq_vector(vp_dev->pci_dev, i));
      38                 :          0 : }
      39                 :            : 
      40                 :            : /* the notify function used when creating a virt queue */
      41                 :          0 : bool vp_notify(struct virtqueue *vq)
      42                 :            : {
      43                 :            :         /* we write the queue's selector into the notification register to
      44                 :            :          * signal the other end */
      45                 :          0 :         iowrite16(vq->index, (void __iomem *)vq->priv);
      46                 :          0 :         return true;
      47                 :            : }
      48                 :            : 
      49                 :            : /* Handle a configuration change: Tell driver if it wants to know. */
      50                 :          0 : static irqreturn_t vp_config_changed(int irq, void *opaque)
      51                 :            : {
      52                 :          0 :         struct virtio_pci_device *vp_dev = opaque;
      53                 :            : 
      54                 :          0 :         virtio_config_changed(&vp_dev->vdev);
      55                 :          0 :         return IRQ_HANDLED;
      56                 :            : }
      57                 :            : 
      58                 :            : /* Notify all virtqueues on an interrupt. */
      59                 :          0 : static irqreturn_t vp_vring_interrupt(int irq, void *opaque)
      60                 :            : {
      61                 :          0 :         struct virtio_pci_device *vp_dev = opaque;
      62                 :          0 :         struct virtio_pci_vq_info *info;
      63                 :          0 :         irqreturn_t ret = IRQ_NONE;
      64                 :          0 :         unsigned long flags;
      65                 :            : 
      66                 :          0 :         spin_lock_irqsave(&vp_dev->lock, flags);
      67         [ #  # ]:          0 :         list_for_each_entry(info, &vp_dev->virtqueues, node) {
      68         [ #  # ]:          0 :                 if (vring_interrupt(irq, info->vq) == IRQ_HANDLED)
      69                 :          0 :                         ret = IRQ_HANDLED;
      70                 :            :         }
      71                 :          0 :         spin_unlock_irqrestore(&vp_dev->lock, flags);
      72                 :            : 
      73                 :          0 :         return ret;
      74                 :            : }
      75                 :            : 
      76                 :            : /* A small wrapper to also acknowledge the interrupt when it's handled.
      77                 :            :  * I really need an EIO hook for the vring so I can ack the interrupt once we
      78                 :            :  * know that we'll be handling the IRQ but before we invoke the callback since
      79                 :            :  * the callback may notify the host which results in the host attempting to
      80                 :            :  * raise an interrupt that we would then mask once we acknowledged the
      81                 :            :  * interrupt. */
      82                 :          0 : static irqreturn_t vp_interrupt(int irq, void *opaque)
      83                 :            : {
      84                 :          0 :         struct virtio_pci_device *vp_dev = opaque;
      85                 :          0 :         u8 isr;
      86                 :            : 
      87                 :            :         /* reading the ISR has the effect of also clearing it so it's very
      88                 :            :          * important to save off the value. */
      89                 :          0 :         isr = ioread8(vp_dev->isr);
      90                 :            : 
      91                 :            :         /* It's definitely not us if the ISR was not high */
      92         [ #  # ]:          0 :         if (!isr)
      93                 :            :                 return IRQ_NONE;
      94                 :            : 
      95                 :            :         /* Configuration change?  Tell driver if it wants to know. */
      96         [ #  # ]:          0 :         if (isr & VIRTIO_PCI_ISR_CONFIG)
      97                 :          0 :                 vp_config_changed(irq, opaque);
      98                 :            : 
      99                 :          0 :         return vp_vring_interrupt(irq, opaque);
     100                 :            : }
     101                 :            : 
     102                 :          0 : static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
     103                 :            :                                    bool per_vq_vectors, struct irq_affinity *desc)
     104                 :            : {
     105         [ #  # ]:          0 :         struct virtio_pci_device *vp_dev = to_vp_device(vdev);
     106         [ #  # ]:          0 :         const char *name = dev_name(&vp_dev->vdev.dev);
     107                 :          0 :         unsigned flags = PCI_IRQ_MSIX;
     108                 :          0 :         unsigned i, v;
     109                 :          0 :         int err = -ENOMEM;
     110                 :            : 
     111                 :          0 :         vp_dev->msix_vectors = nvectors;
     112                 :            : 
     113                 :          0 :         vp_dev->msix_names = kmalloc_array(nvectors,
     114                 :            :                                            sizeof(*vp_dev->msix_names),
     115                 :            :                                            GFP_KERNEL);
     116         [ #  # ]:          0 :         if (!vp_dev->msix_names)
     117                 :          0 :                 goto error;
     118                 :          0 :         vp_dev->msix_affinity_masks
     119                 :          0 :                 = kcalloc(nvectors, sizeof(*vp_dev->msix_affinity_masks),
     120                 :            :                           GFP_KERNEL);
     121         [ #  # ]:          0 :         if (!vp_dev->msix_affinity_masks)
     122                 :          0 :                 goto error;
     123                 :          0 :         for (i = 0; i < nvectors; ++i)
     124                 :            :                 if (!alloc_cpumask_var(&vp_dev->msix_affinity_masks[i],
     125                 :            :                                         GFP_KERNEL))
     126                 :            :                         goto error;
     127                 :            : 
     128         [ #  # ]:          0 :         if (desc) {
     129                 :          0 :                 flags |= PCI_IRQ_AFFINITY;
     130                 :          0 :                 desc->pre_vectors++; /* virtio config vector */
     131                 :            :         }
     132                 :            : 
     133                 :          0 :         err = pci_alloc_irq_vectors_affinity(vp_dev->pci_dev, nvectors,
     134                 :            :                                              nvectors, flags, desc);
     135         [ #  # ]:          0 :         if (err < 0)
     136                 :          0 :                 goto error;
     137                 :          0 :         vp_dev->msix_enabled = 1;
     138                 :            : 
     139                 :            :         /* Set the vector used for configuration */
     140                 :          0 :         v = vp_dev->msix_used_vectors;
     141                 :          0 :         snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
     142                 :            :                  "%s-config", name);
     143                 :          0 :         err = request_irq(pci_irq_vector(vp_dev->pci_dev, v),
     144                 :          0 :                           vp_config_changed, 0, vp_dev->msix_names[v],
     145                 :            :                           vp_dev);
     146         [ #  # ]:          0 :         if (err)
     147                 :          0 :                 goto error;
     148                 :          0 :         ++vp_dev->msix_used_vectors;
     149                 :            : 
     150                 :          0 :         v = vp_dev->config_vector(vp_dev, v);
     151                 :            :         /* Verify we had enough resources to assign the vector */
     152         [ #  # ]:          0 :         if (v == VIRTIO_MSI_NO_VECTOR) {
     153                 :          0 :                 err = -EBUSY;
     154                 :          0 :                 goto error;
     155                 :            :         }
     156                 :            : 
     157         [ #  # ]:          0 :         if (!per_vq_vectors) {
     158                 :            :                 /* Shared vector for all VQs */
     159                 :          0 :                 v = vp_dev->msix_used_vectors;
     160                 :          0 :                 snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
     161                 :            :                          "%s-virtqueues", name);
     162                 :          0 :                 err = request_irq(pci_irq_vector(vp_dev->pci_dev, v),
     163                 :          0 :                                   vp_vring_interrupt, 0, vp_dev->msix_names[v],
     164                 :            :                                   vp_dev);
     165         [ #  # ]:          0 :                 if (err)
     166                 :          0 :                         goto error;
     167                 :          0 :                 ++vp_dev->msix_used_vectors;
     168                 :            :         }
     169                 :            :         return 0;
     170                 :            : error:
     171                 :            :         return err;
     172                 :            : }
     173                 :            : 
     174                 :          0 : static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned index,
     175                 :            :                                      void (*callback)(struct virtqueue *vq),
     176                 :            :                                      const char *name,
     177                 :            :                                      bool ctx,
     178                 :            :                                      u16 msix_vec)
     179                 :            : {
     180                 :          0 :         struct virtio_pci_device *vp_dev = to_vp_device(vdev);
     181                 :          0 :         struct virtio_pci_vq_info *info = kmalloc(sizeof *info, GFP_KERNEL);
     182                 :          0 :         struct virtqueue *vq;
     183                 :          0 :         unsigned long flags;
     184                 :            : 
     185                 :            :         /* fill out our structure that represents an active queue */
     186         [ #  # ]:          0 :         if (!info)
     187                 :            :                 return ERR_PTR(-ENOMEM);
     188                 :            : 
     189                 :          0 :         vq = vp_dev->setup_vq(vp_dev, info, index, callback, name, ctx,
     190                 :            :                               msix_vec);
     191         [ #  # ]:          0 :         if (IS_ERR(vq))
     192                 :          0 :                 goto out_info;
     193                 :            : 
     194                 :          0 :         info->vq = vq;
     195         [ #  # ]:          0 :         if (callback) {
     196                 :          0 :                 spin_lock_irqsave(&vp_dev->lock, flags);
     197                 :          0 :                 list_add(&info->node, &vp_dev->virtqueues);
     198                 :          0 :                 spin_unlock_irqrestore(&vp_dev->lock, flags);
     199                 :            :         } else {
     200                 :          0 :                 INIT_LIST_HEAD(&info->node);
     201                 :            :         }
     202                 :            : 
     203                 :          0 :         vp_dev->vqs[index] = info;
     204                 :          0 :         return vq;
     205                 :            : 
     206                 :            : out_info:
     207                 :          0 :         kfree(info);
     208                 :          0 :         return vq;
     209                 :            : }
     210                 :            : 
     211                 :            : static void vp_del_vq(struct virtqueue *vq)
     212                 :            : {
     213                 :            :         struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
     214                 :            :         struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
     215                 :            :         unsigned long flags;
     216                 :            : 
     217                 :            :         spin_lock_irqsave(&vp_dev->lock, flags);
     218                 :            :         list_del(&info->node);
     219                 :            :         spin_unlock_irqrestore(&vp_dev->lock, flags);
     220                 :            : 
     221                 :            :         vp_dev->del_vq(info);
     222                 :            :         kfree(info);
     223                 :            : }
     224                 :            : 
     225                 :            : /* the config->del_vqs() implementation */
     226                 :          0 : void vp_del_vqs(struct virtio_device *vdev)
     227                 :            : {
     228                 :          0 :         struct virtio_pci_device *vp_dev = to_vp_device(vdev);
     229                 :          0 :         struct virtqueue *vq, *n;
     230                 :          0 :         int i;
     231                 :            : 
     232         [ #  # ]:          0 :         list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
     233         [ #  # ]:          0 :                 if (vp_dev->per_vq_vectors) {
     234                 :          0 :                         int v = vp_dev->vqs[vq->index]->msix_vector;
     235                 :            : 
     236         [ #  # ]:          0 :                         if (v != VIRTIO_MSI_NO_VECTOR) {
     237                 :          0 :                                 int irq = pci_irq_vector(vp_dev->pci_dev, v);
     238                 :            : 
     239                 :          0 :                                 irq_set_affinity_hint(irq, NULL);
     240                 :          0 :                                 free_irq(irq, vq);
     241                 :            :                         }
     242                 :            :                 }
     243                 :          0 :                 vp_del_vq(vq);
     244                 :            :         }
     245                 :          0 :         vp_dev->per_vq_vectors = false;
     246                 :            : 
     247         [ #  # ]:          0 :         if (vp_dev->intx_enabled) {
     248                 :          0 :                 free_irq(vp_dev->pci_dev->irq, vp_dev);
     249                 :          0 :                 vp_dev->intx_enabled = 0;
     250                 :            :         }
     251                 :            : 
     252         [ #  # ]:          0 :         for (i = 0; i < vp_dev->msix_used_vectors; ++i)
     253                 :          0 :                 free_irq(pci_irq_vector(vp_dev->pci_dev, i), vp_dev);
     254                 :            : 
     255         [ #  # ]:          0 :         if (vp_dev->msix_affinity_masks) {
     256         [ #  # ]:          0 :                 for (i = 0; i < vp_dev->msix_vectors; i++)
     257                 :          0 :                         if (vp_dev->msix_affinity_masks[i])
     258                 :            :                                 free_cpumask_var(vp_dev->msix_affinity_masks[i]);
     259                 :            :         }
     260                 :            : 
     261         [ #  # ]:          0 :         if (vp_dev->msix_enabled) {
     262                 :            :                 /* Disable the vector used for configuration */
     263                 :          0 :                 vp_dev->config_vector(vp_dev, VIRTIO_MSI_NO_VECTOR);
     264                 :            : 
     265                 :          0 :                 pci_free_irq_vectors(vp_dev->pci_dev);
     266                 :          0 :                 vp_dev->msix_enabled = 0;
     267                 :            :         }
     268                 :            : 
     269                 :          0 :         vp_dev->msix_vectors = 0;
     270                 :          0 :         vp_dev->msix_used_vectors = 0;
     271                 :          0 :         kfree(vp_dev->msix_names);
     272                 :          0 :         vp_dev->msix_names = NULL;
     273                 :          0 :         kfree(vp_dev->msix_affinity_masks);
     274                 :          0 :         vp_dev->msix_affinity_masks = NULL;
     275                 :          0 :         kfree(vp_dev->vqs);
     276                 :          0 :         vp_dev->vqs = NULL;
     277                 :          0 : }
     278                 :            : 
     279                 :          0 : static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs,
     280                 :            :                 struct virtqueue *vqs[], vq_callback_t *callbacks[],
     281                 :            :                 const char * const names[], bool per_vq_vectors,
     282                 :            :                 const bool *ctx,
     283                 :            :                 struct irq_affinity *desc)
     284                 :            : {
     285                 :          0 :         struct virtio_pci_device *vp_dev = to_vp_device(vdev);
     286                 :          0 :         u16 msix_vec;
     287                 :          0 :         int i, err, nvectors, allocated_vectors, queue_idx = 0;
     288                 :            : 
     289                 :          0 :         vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
     290         [ #  # ]:          0 :         if (!vp_dev->vqs)
     291                 :            :                 return -ENOMEM;
     292                 :            : 
     293         [ #  # ]:          0 :         if (per_vq_vectors) {
     294                 :            :                 /* Best option: one for change interrupt, one per vq. */
     295                 :            :                 nvectors = 1;
     296         [ #  # ]:          0 :                 for (i = 0; i < nvqs; ++i)
     297   [ #  #  #  # ]:          0 :                         if (names[i] && callbacks[i])
     298                 :          0 :                                 ++nvectors;
     299                 :            :         } else {
     300                 :            :                 /* Second best: one for change, shared for all vqs. */
     301                 :            :                 nvectors = 2;
     302                 :            :         }
     303                 :            : 
     304         [ #  # ]:          0 :         err = vp_request_msix_vectors(vdev, nvectors, per_vq_vectors,
     305                 :            :                                       per_vq_vectors ? desc : NULL);
     306         [ #  # ]:          0 :         if (err)
     307                 :          0 :                 goto error_find;
     308                 :            : 
     309                 :          0 :         vp_dev->per_vq_vectors = per_vq_vectors;
     310                 :          0 :         allocated_vectors = vp_dev->msix_used_vectors;
     311         [ #  # ]:          0 :         for (i = 0; i < nvqs; ++i) {
     312         [ #  # ]:          0 :                 if (!names[i]) {
     313                 :          0 :                         vqs[i] = NULL;
     314                 :          0 :                         continue;
     315                 :            :                 }
     316                 :            : 
     317         [ #  # ]:          0 :                 if (!callbacks[i])
     318                 :            :                         msix_vec = VIRTIO_MSI_NO_VECTOR;
     319         [ #  # ]:          0 :                 else if (vp_dev->per_vq_vectors)
     320                 :          0 :                         msix_vec = allocated_vectors++;
     321                 :            :                 else
     322                 :            :                         msix_vec = VP_MSIX_VQ_VECTOR;
     323                 :          0 :                 vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i],
     324   [ #  #  #  # ]:          0 :                                      ctx ? ctx[i] : false,
     325                 :            :                                      msix_vec);
     326         [ #  # ]:          0 :                 if (IS_ERR(vqs[i])) {
     327                 :          0 :                         err = PTR_ERR(vqs[i]);
     328                 :          0 :                         goto error_find;
     329                 :            :                 }
     330                 :            : 
     331   [ #  #  #  # ]:          0 :                 if (!vp_dev->per_vq_vectors || msix_vec == VIRTIO_MSI_NO_VECTOR)
     332                 :          0 :                         continue;
     333                 :            : 
     334                 :            :                 /* allocate per-vq irq if available and necessary */
     335         [ #  # ]:          0 :                 snprintf(vp_dev->msix_names[msix_vec],
     336                 :            :                          sizeof *vp_dev->msix_names,
     337                 :            :                          "%s-%s",
     338                 :            :                          dev_name(&vp_dev->vdev.dev), names[i]);
     339                 :          0 :                 err = request_irq(pci_irq_vector(vp_dev->pci_dev, msix_vec),
     340                 :            :                                   vring_interrupt, 0,
     341                 :          0 :                                   vp_dev->msix_names[msix_vec],
     342                 :            :                                   vqs[i]);
     343         [ #  # ]:          0 :                 if (err)
     344                 :          0 :                         goto error_find;
     345                 :            :         }
     346                 :            :         return 0;
     347                 :            : 
     348                 :          0 : error_find:
     349                 :          0 :         vp_del_vqs(vdev);
     350                 :          0 :         return err;
     351                 :            : }
     352                 :            : 
     353                 :          0 : static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs,
     354                 :            :                 struct virtqueue *vqs[], vq_callback_t *callbacks[],
     355                 :            :                 const char * const names[], const bool *ctx)
     356                 :            : {
     357                 :          0 :         struct virtio_pci_device *vp_dev = to_vp_device(vdev);
     358                 :          0 :         int i, err, queue_idx = 0;
     359                 :            : 
     360                 :          0 :         vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL);
     361         [ #  # ]:          0 :         if (!vp_dev->vqs)
     362                 :            :                 return -ENOMEM;
     363                 :            : 
     364         [ #  # ]:          0 :         err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED,
     365                 :            :                         dev_name(&vdev->dev), vp_dev);
     366         [ #  # ]:          0 :         if (err)
     367                 :          0 :                 goto out_del_vqs;
     368                 :            : 
     369                 :          0 :         vp_dev->intx_enabled = 1;
     370                 :          0 :         vp_dev->per_vq_vectors = false;
     371         [ #  # ]:          0 :         for (i = 0; i < nvqs; ++i) {
     372         [ #  # ]:          0 :                 if (!names[i]) {
     373                 :          0 :                         vqs[i] = NULL;
     374                 :          0 :                         continue;
     375                 :            :                 }
     376                 :          0 :                 vqs[i] = vp_setup_vq(vdev, queue_idx++, callbacks[i], names[i],
     377   [ #  #  #  # ]:          0 :                                      ctx ? ctx[i] : false,
     378                 :            :                                      VIRTIO_MSI_NO_VECTOR);
     379         [ #  # ]:          0 :                 if (IS_ERR(vqs[i])) {
     380                 :          0 :                         err = PTR_ERR(vqs[i]);
     381                 :          0 :                         goto out_del_vqs;
     382                 :            :                 }
     383                 :            :         }
     384                 :            : 
     385                 :            :         return 0;
     386                 :          0 : out_del_vqs:
     387                 :          0 :         vp_del_vqs(vdev);
     388                 :          0 :         return err;
     389                 :            : }
     390                 :            : 
     391                 :            : /* the config->find_vqs() implementation */
     392                 :          0 : int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
     393                 :            :                 struct virtqueue *vqs[], vq_callback_t *callbacks[],
     394                 :            :                 const char * const names[], const bool *ctx,
     395                 :            :                 struct irq_affinity *desc)
     396                 :            : {
     397                 :          0 :         int err;
     398                 :            : 
     399                 :            :         /* Try MSI-X with one vector per queue. */
     400                 :          0 :         err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, true, ctx, desc);
     401         [ #  # ]:          0 :         if (!err)
     402                 :            :                 return 0;
     403                 :            :         /* Fallback: MSI-X with one vector for config, one shared for queues. */
     404                 :          0 :         err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, false, ctx, desc);
     405         [ #  # ]:          0 :         if (!err)
     406                 :            :                 return 0;
     407                 :            :         /* Finally fall back to regular interrupts. */
     408                 :          0 :         return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names, ctx);
     409                 :            : }
     410                 :            : 
     411                 :          0 : const char *vp_bus_name(struct virtio_device *vdev)
     412                 :            : {
     413         [ #  # ]:          0 :         struct virtio_pci_device *vp_dev = to_vp_device(vdev);
     414                 :            : 
     415         [ #  # ]:          0 :         return pci_name(vp_dev->pci_dev);
     416                 :            : }
     417                 :            : 
     418                 :            : /* Setup the affinity for a virtqueue:
     419                 :            :  * - force the affinity for per vq vector
     420                 :            :  * - OR over all affinities for shared MSI
     421                 :            :  * - ignore the affinity request if we're using INTX
     422                 :            :  */
     423                 :          0 : int vp_set_vq_affinity(struct virtqueue *vq, const struct cpumask *cpu_mask)
     424                 :            : {
     425                 :          0 :         struct virtio_device *vdev = vq->vdev;
     426         [ #  # ]:          0 :         struct virtio_pci_device *vp_dev = to_vp_device(vdev);
     427                 :          0 :         struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
     428                 :          0 :         struct cpumask *mask;
     429                 :          0 :         unsigned int irq;
     430                 :            : 
     431         [ #  # ]:          0 :         if (!vq->callback)
     432                 :            :                 return -EINVAL;
     433                 :            : 
     434         [ #  # ]:          0 :         if (vp_dev->msix_enabled) {
     435                 :          0 :                 mask = vp_dev->msix_affinity_masks[info->msix_vector];
     436                 :          0 :                 irq = pci_irq_vector(vp_dev->pci_dev, info->msix_vector);
     437         [ #  # ]:          0 :                 if (!cpu_mask)
     438                 :          0 :                         irq_set_affinity_hint(irq, NULL);
     439                 :            :                 else {
     440                 :          0 :                         cpumask_copy(mask, cpu_mask);
     441                 :          0 :                         irq_set_affinity_hint(irq, mask);
     442                 :            :                 }
     443                 :            :         }
     444                 :            :         return 0;
     445                 :            : }
     446                 :            : 
     447                 :          0 : const struct cpumask *vp_get_vq_affinity(struct virtio_device *vdev, int index)
     448                 :            : {
     449         [ #  # ]:          0 :         struct virtio_pci_device *vp_dev = to_vp_device(vdev);
     450                 :            : 
     451         [ #  # ]:          0 :         if (!vp_dev->per_vq_vectors ||
     452         [ #  # ]:          0 :             vp_dev->vqs[index]->msix_vector == VIRTIO_MSI_NO_VECTOR)
     453                 :            :                 return NULL;
     454                 :            : 
     455                 :          0 :         return pci_irq_get_affinity(vp_dev->pci_dev,
     456                 :            :                                     vp_dev->vqs[index]->msix_vector);
     457                 :            : }
     458                 :            : 
     459                 :            : #ifdef CONFIG_PM_SLEEP
     460                 :          0 : static int virtio_pci_freeze(struct device *dev)
     461                 :            : {
     462                 :          0 :         struct pci_dev *pci_dev = to_pci_dev(dev);
     463                 :          0 :         struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
     464                 :          0 :         int ret;
     465                 :            : 
     466                 :          0 :         ret = virtio_device_freeze(&vp_dev->vdev);
     467                 :            : 
     468         [ #  # ]:          0 :         if (!ret)
     469                 :          0 :                 pci_disable_device(pci_dev);
     470                 :          0 :         return ret;
     471                 :            : }
     472                 :            : 
     473                 :          0 : static int virtio_pci_restore(struct device *dev)
     474                 :            : {
     475                 :          0 :         struct pci_dev *pci_dev = to_pci_dev(dev);
     476                 :          0 :         struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
     477                 :          0 :         int ret;
     478                 :            : 
     479                 :          0 :         ret = pci_enable_device(pci_dev);
     480         [ #  # ]:          0 :         if (ret)
     481                 :            :                 return ret;
     482                 :            : 
     483                 :          0 :         pci_set_master(pci_dev);
     484                 :          0 :         return virtio_device_restore(&vp_dev->vdev);
     485                 :            : }
     486                 :            : 
     487                 :            : static const struct dev_pm_ops virtio_pci_pm_ops = {
     488                 :            :         SET_SYSTEM_SLEEP_PM_OPS(virtio_pci_freeze, virtio_pci_restore)
     489                 :            : };
     490                 :            : #endif
     491                 :            : 
     492                 :            : 
     493                 :            : /* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */
     494                 :            : static const struct pci_device_id virtio_pci_id_table[] = {
     495                 :            :         { PCI_DEVICE(PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_ANY_ID) },
     496                 :            :         { 0 }
     497                 :            : };
     498                 :            : 
     499                 :            : MODULE_DEVICE_TABLE(pci, virtio_pci_id_table);
     500                 :            : 
     501                 :          0 : static void virtio_pci_release_dev(struct device *_d)
     502                 :            : {
     503                 :          0 :         struct virtio_device *vdev = dev_to_virtio(_d);
     504                 :          0 :         struct virtio_pci_device *vp_dev = to_vp_device(vdev);
     505                 :            : 
     506                 :            :         /* As struct device is a kobject, it's not safe to
     507                 :            :          * free the memory (including the reference counter itself)
     508                 :            :          * until it's release callback. */
     509                 :          0 :         kfree(vp_dev);
     510                 :          0 : }
     511                 :            : 
     512                 :          0 : static int virtio_pci_probe(struct pci_dev *pci_dev,
     513                 :            :                             const struct pci_device_id *id)
     514                 :            : {
     515                 :          0 :         struct virtio_pci_device *vp_dev, *reg_dev = NULL;
     516                 :          0 :         int rc;
     517                 :            : 
     518                 :            :         /* allocate our structure and fill it out */
     519                 :          0 :         vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL);
     520         [ #  # ]:          0 :         if (!vp_dev)
     521                 :            :                 return -ENOMEM;
     522                 :            : 
     523                 :          0 :         pci_set_drvdata(pci_dev, vp_dev);
     524                 :          0 :         vp_dev->vdev.dev.parent = &pci_dev->dev;
     525                 :          0 :         vp_dev->vdev.dev.release = virtio_pci_release_dev;
     526                 :          0 :         vp_dev->pci_dev = pci_dev;
     527                 :          0 :         INIT_LIST_HEAD(&vp_dev->virtqueues);
     528                 :          0 :         spin_lock_init(&vp_dev->lock);
     529                 :            : 
     530                 :            :         /* enable the device */
     531                 :          0 :         rc = pci_enable_device(pci_dev);
     532         [ #  # ]:          0 :         if (rc)
     533                 :          0 :                 goto err_enable_device;
     534                 :            : 
     535         [ #  # ]:          0 :         if (force_legacy) {
     536                 :          0 :                 rc = virtio_pci_legacy_probe(vp_dev);
     537                 :            :                 /* Also try modern mode if we can't map BAR0 (no IO space). */
     538         [ #  # ]:          0 :                 if (rc == -ENODEV || rc == -ENOMEM)
     539                 :          0 :                         rc = virtio_pci_modern_probe(vp_dev);
     540         [ #  # ]:          0 :                 if (rc)
     541                 :          0 :                         goto err_probe;
     542                 :            :         } else {
     543                 :          0 :                 rc = virtio_pci_modern_probe(vp_dev);
     544         [ #  # ]:          0 :                 if (rc == -ENODEV)
     545                 :          0 :                         rc = virtio_pci_legacy_probe(vp_dev);
     546         [ #  # ]:          0 :                 if (rc)
     547                 :          0 :                         goto err_probe;
     548                 :            :         }
     549                 :            : 
     550                 :          0 :         pci_set_master(pci_dev);
     551                 :            : 
     552                 :          0 :         rc = register_virtio_device(&vp_dev->vdev);
     553                 :          0 :         reg_dev = vp_dev;
     554         [ #  # ]:          0 :         if (rc)
     555                 :          0 :                 goto err_register;
     556                 :            : 
     557                 :            :         return 0;
     558                 :            : 
     559                 :            : err_register:
     560         [ #  # ]:          0 :         if (vp_dev->ioaddr)
     561                 :          0 :              virtio_pci_legacy_remove(vp_dev);
     562                 :            :         else
     563                 :          0 :              virtio_pci_modern_remove(vp_dev);
     564                 :          0 : err_probe:
     565                 :          0 :         pci_disable_device(pci_dev);
     566                 :            : err_enable_device:
     567         [ #  # ]:          0 :         if (reg_dev)
     568                 :          0 :                 put_device(&vp_dev->vdev.dev);
     569                 :            :         else
     570                 :          0 :                 kfree(vp_dev);
     571                 :            :         return rc;
     572                 :            : }
     573                 :            : 
     574                 :          0 : static void virtio_pci_remove(struct pci_dev *pci_dev)
     575                 :            : {
     576                 :          0 :         struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
     577                 :          0 :         struct device *dev = get_device(&vp_dev->vdev.dev);
     578                 :            : 
     579                 :          0 :         pci_disable_sriov(pci_dev);
     580                 :            : 
     581                 :          0 :         unregister_virtio_device(&vp_dev->vdev);
     582                 :            : 
     583         [ #  # ]:          0 :         if (vp_dev->ioaddr)
     584                 :          0 :                 virtio_pci_legacy_remove(vp_dev);
     585                 :            :         else
     586                 :          0 :                 virtio_pci_modern_remove(vp_dev);
     587                 :            : 
     588                 :          0 :         pci_disable_device(pci_dev);
     589                 :          0 :         put_device(dev);
     590                 :          0 : }
     591                 :            : 
     592                 :          0 : static int virtio_pci_sriov_configure(struct pci_dev *pci_dev, int num_vfs)
     593                 :            : {
     594                 :          0 :         struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
     595                 :          0 :         struct virtio_device *vdev = &vp_dev->vdev;
     596                 :          0 :         int ret;
     597                 :            : 
     598         [ #  # ]:          0 :         if (!(vdev->config->get_status(vdev) & VIRTIO_CONFIG_S_DRIVER_OK))
     599                 :            :                 return -EBUSY;
     600                 :            : 
     601         [ #  # ]:          0 :         if (!__virtio_test_bit(vdev, VIRTIO_F_SR_IOV))
     602                 :            :                 return -EINVAL;
     603                 :            : 
     604         [ #  # ]:          0 :         if (pci_vfs_assigned(pci_dev))
     605                 :            :                 return -EPERM;
     606                 :            : 
     607         [ #  # ]:          0 :         if (num_vfs == 0) {
     608                 :            :                 pci_disable_sriov(pci_dev);
     609                 :            :                 return 0;
     610                 :            :         }
     611                 :            : 
     612                 :          0 :         ret = pci_enable_sriov(pci_dev, num_vfs);
     613                 :          0 :         if (ret < 0)
     614                 :          0 :                 return ret;
     615                 :            : 
     616                 :            :         return num_vfs;
     617                 :            : }
     618                 :            : 
     619                 :            : static struct pci_driver virtio_pci_driver = {
     620                 :            :         .name           = "virtio-pci",
     621                 :            :         .id_table       = virtio_pci_id_table,
     622                 :            :         .probe          = virtio_pci_probe,
     623                 :            :         .remove         = virtio_pci_remove,
     624                 :            : #ifdef CONFIG_PM_SLEEP
     625                 :            :         .driver.pm      = &virtio_pci_pm_ops,
     626                 :            : #endif
     627                 :            :         .sriov_configure = virtio_pci_sriov_configure,
     628                 :            : };
     629                 :            : 
     630                 :         13 : module_pci_driver(virtio_pci_driver);
     631                 :            : 
     632                 :            : MODULE_AUTHOR("Anthony Liguori <aliguori@us.ibm.com>");
     633                 :            : MODULE_DESCRIPTION("virtio-pci");
     634                 :            : MODULE_LICENSE("GPL");
     635                 :            : MODULE_VERSION("1");

Generated by: LCOV version 1.14