return container_of(hw, struct ifcvf_adapter, vf);
 }
 
+u16 ifcvf_set_vq_vector(struct ifcvf_hw *hw, u16 qid, int vector)
+{
+       struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg;
+
+       vp_iowrite16(qid, &cfg->queue_select);
+       vp_iowrite16(vector, &cfg->queue_msix_vector);
+
+       return vp_ioread16(&cfg->queue_msix_vector);
+}
+
+u16 ifcvf_set_config_vector(struct ifcvf_hw *hw, int vector)
+{
+       struct virtio_pci_common_cfg __iomem *cfg = hw->common_cfg;
+
+       cfg = hw->common_cfg;
+       vp_iowrite16(vector,  &cfg->msix_config);
+
+       return vp_ioread16(&cfg->msix_config);
+}
+
 static void __iomem *get_cap_addr(struct ifcvf_hw *hw,
                                  struct virtio_pci_cap *cap)
 {
                        notify_off * hw->notify_off_multiplier;
                hw->vring[i].notify_pa = hw->notify_base_pa +
                        notify_off * hw->notify_off_multiplier;
+               hw->vring[i].irq = -EINVAL;
        }
 
        hw->lm_cfg = hw->base[IFCVF_LM_BAR];
                  hw->common_cfg, hw->notify_base, hw->isr,
                  hw->dev_cfg, hw->notify_off_multiplier);
 
+       hw->vqs_reused_irq = -EINVAL;
+       hw->config_irq = -EINVAL;
+
        return 0;
 }
 
 
        ifcvf = vf_to_adapter(hw);
        cfg = hw->common_cfg;
-       vp_iowrite16(IFCVF_MSI_CONFIG_OFF, &cfg->msix_config);
-
-       if (vp_ioread16(&cfg->msix_config) == VIRTIO_MSI_NO_VECTOR) {
-               IFCVF_ERR(ifcvf->pdev, "No msix vector for device config\n");
-               return -EINVAL;
-       }
-
        for (i = 0; i < hw->nr_vring; i++) {
                if (!hw->vring[i].ready)
                        break;
                vp_iowrite64_twopart(hw->vring[i].used, &cfg->queue_used_lo,
                                     &cfg->queue_used_hi);
                vp_iowrite16(hw->vring[i].size, &cfg->queue_size);
-               vp_iowrite16(i + IFCVF_MSI_QUEUE_OFF, &cfg->queue_msix_vector);
-
-               if (vp_ioread16(&cfg->queue_msix_vector) ==
-                   VIRTIO_MSI_NO_VECTOR) {
-                       IFCVF_ERR(ifcvf->pdev,
-                                 "No msix vector for queue %u\n", i);
-                       return -EINVAL;
-               }
-
                ifcvf_set_vq_state(hw, i, hw->vring[i].last_avail_idx);
                vp_iowrite16(1, &cfg->queue_enable);
        }
        u32 i;
 
        cfg = hw->common_cfg;
-       vp_iowrite16(VIRTIO_MSI_NO_VECTOR, &cfg->msix_config);
-
+       ifcvf_set_config_vector(hw, VIRTIO_MSI_NO_VECTOR);
        for (i = 0; i < hw->nr_vring; i++) {
-               vp_iowrite16(i, &cfg->queue_select);
-               vp_iowrite16(VIRTIO_MSI_NO_VECTOR, &cfg->queue_msix_vector);
+               ifcvf_set_vq_vector(hw, i, VIRTIO_MSI_NO_VECTOR);
        }
-
-       vp_ioread16(&cfg->queue_msix_vector);
 }
 
 int ifcvf_start_hw(struct ifcvf_hw *hw)
 
        return IRQ_HANDLED;
 }
 
-static irqreturn_t ifcvf_intr_handler(int irq, void *arg)
+static irqreturn_t ifcvf_vq_intr_handler(int irq, void *arg)
 {
        struct vring_info *vring = arg;
 
        return IRQ_HANDLED;
 }
 
+static irqreturn_t ifcvf_vqs_reused_intr_handler(int irq, void *arg)
+{
+       struct ifcvf_hw *vf = arg;
+       struct vring_info *vring;
+       int i;
+
+       for (i = 0; i < vf->nr_vring; i++) {
+               vring = &vf->vring[i];
+               if (vring->cb.callback)
+                       vring->cb.callback(vring->cb.private);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t ifcvf_dev_intr_handler(int irq, void *arg)
+{
+       struct ifcvf_hw *vf = arg;
+       u8 isr;
+
+       isr = vp_ioread8(vf->isr);
+       if (isr & VIRTIO_PCI_ISR_CONFIG)
+               ifcvf_config_changed(irq, arg);
+
+       return ifcvf_vqs_reused_intr_handler(irq, arg);
+}
+
 static void ifcvf_free_irq_vectors(void *data)
 {
        pci_free_irq_vectors(data);
 }
 
-static void ifcvf_free_irq(struct ifcvf_adapter *adapter, int queues)
+static void ifcvf_free_per_vq_irq(struct ifcvf_adapter *adapter)
 {
        struct pci_dev *pdev = adapter->pdev;
        struct ifcvf_hw *vf = &adapter->vf;
        int i;
 
+       for (i = 0; i < vf->nr_vring; i++) {
+               if (vf->vring[i].irq != -EINVAL) {
+                       devm_free_irq(&pdev->dev, vf->vring[i].irq, &vf->vring[i]);
+                       vf->vring[i].irq = -EINVAL;
+               }
+       }
+}
 
-       for (i = 0; i < queues; i++) {
-               devm_free_irq(&pdev->dev, vf->vring[i].irq, &vf->vring[i]);
-               vf->vring[i].irq = -EINVAL;
+static void ifcvf_free_vqs_reused_irq(struct ifcvf_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       struct ifcvf_hw *vf = &adapter->vf;
+
+       if (vf->vqs_reused_irq != -EINVAL) {
+               devm_free_irq(&pdev->dev, vf->vqs_reused_irq, vf);
+               vf->vqs_reused_irq = -EINVAL;
        }
 
-       devm_free_irq(&pdev->dev, vf->config_irq, vf);
+}
+
+static void ifcvf_free_vq_irq(struct ifcvf_adapter *adapter)
+{
+       struct ifcvf_hw *vf = &adapter->vf;
+
+       if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG)
+               ifcvf_free_per_vq_irq(adapter);
+       else
+               ifcvf_free_vqs_reused_irq(adapter);
+}
+
+static void ifcvf_free_config_irq(struct ifcvf_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       struct ifcvf_hw *vf = &adapter->vf;
+
+       if (vf->config_irq == -EINVAL)
+               return;
+
+       /* If the irq is shared by all vqs and the config interrupt,
+        * it is already freed in ifcvf_free_vq_irq, so here only
+        * need to free config irq when msix_vector_status != MSIX_VECTOR_DEV_SHARED
+        */
+       if (vf->msix_vector_status != MSIX_VECTOR_DEV_SHARED) {
+               devm_free_irq(&pdev->dev, vf->config_irq, vf);
+               vf->config_irq = -EINVAL;
+       }
+}
+
+static void ifcvf_free_irq(struct ifcvf_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+
+       ifcvf_free_vq_irq(adapter);
+       ifcvf_free_config_irq(adapter);
        ifcvf_free_irq_vectors(pdev);
 }
 
        return ret;
 }
 
-static int ifcvf_request_irq(struct ifcvf_adapter *adapter)
+static int ifcvf_request_per_vq_irq(struct ifcvf_adapter *adapter)
 {
        struct pci_dev *pdev = adapter->pdev;
        struct ifcvf_hw *vf = &adapter->vf;
-       int vector, nvectors, i, ret, irq;
+       int i, vector, ret, irq;
 
-       nvectors = ifcvf_alloc_vectors(adapter);
-       if (nvectors <= 0)
-               return -EFAULT;
+       vf->vqs_reused_irq = -EINVAL;
+       for (i = 0; i < vf->nr_vring; i++) {
+               snprintf(vf->vring[i].msix_name, 256, "ifcvf[%s]-%d\n", pci_name(pdev), i);
+               vector = i;
+               irq = pci_irq_vector(pdev, vector);
+               ret = devm_request_irq(&pdev->dev, irq,
+                                      ifcvf_vq_intr_handler, 0,
+                                      vf->vring[i].msix_name,
+                                      &vf->vring[i]);
+               if (ret) {
+                       IFCVF_ERR(pdev, "Failed to request irq for vq %d\n", i);
+                       goto err;
+               }
+
+               vf->vring[i].irq = irq;
+               ret = ifcvf_set_vq_vector(vf, i, vector);
+               if (ret == VIRTIO_MSI_NO_VECTOR) {
+                       IFCVF_ERR(pdev, "No msix vector for vq %u\n", i);
+                       goto err;
+               }
+       }
+
+       return 0;
+err:
+       ifcvf_free_irq(adapter);
+
+       return -EFAULT;
+}
+
+static int ifcvf_request_vqs_reused_irq(struct ifcvf_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       struct ifcvf_hw *vf = &adapter->vf;
+       int i, vector, ret, irq;
+
+       vector = 0;
+       snprintf(vf->vring[0].msix_name, 256, "ifcvf[%s]-vqs-reused-irq\n", pci_name(pdev));
+       irq = pci_irq_vector(pdev, vector);
+       ret = devm_request_irq(&pdev->dev, irq,
+                              ifcvf_vqs_reused_intr_handler, 0,
+                              vf->vring[0].msix_name, vf);
+       if (ret) {
+               IFCVF_ERR(pdev, "Failed to request reused irq for the device\n");
+               goto err;
+       }
+
+       vf->vqs_reused_irq = irq;
+       for (i = 0; i < vf->nr_vring; i++) {
+               vf->vring[i].irq = -EINVAL;
+               ret = ifcvf_set_vq_vector(vf, i, vector);
+               if (ret == VIRTIO_MSI_NO_VECTOR) {
+                       IFCVF_ERR(pdev, "No msix vector for vq %u\n", i);
+                       goto err;
+               }
+       }
+
+       return 0;
+err:
+       ifcvf_free_irq(adapter);
+
+       return -EFAULT;
+}
+
+static int ifcvf_request_dev_irq(struct ifcvf_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       struct ifcvf_hw *vf = &adapter->vf;
+       int i, vector, ret, irq;
+
+       vector = 0;
+       snprintf(vf->vring[0].msix_name, 256, "ifcvf[%s]-dev-irq\n", pci_name(pdev));
+       irq = pci_irq_vector(pdev, vector);
+       ret = devm_request_irq(&pdev->dev, irq,
+                              ifcvf_dev_intr_handler, 0,
+                              vf->vring[0].msix_name, vf);
+       if (ret) {
+               IFCVF_ERR(pdev, "Failed to request irq for the device\n");
+               goto err;
+       }
+
+       vf->vqs_reused_irq = irq;
+       for (i = 0; i < vf->nr_vring; i++) {
+               vf->vring[i].irq = -EINVAL;
+               ret = ifcvf_set_vq_vector(vf, i, vector);
+               if (ret == VIRTIO_MSI_NO_VECTOR) {
+                       IFCVF_ERR(pdev, "No msix vector for vq %u\n", i);
+                       goto err;
+               }
+       }
+
+       vf->config_irq = irq;
+       ret = ifcvf_set_config_vector(vf, vector);
+       if (ret == VIRTIO_MSI_NO_VECTOR) {
+               IFCVF_ERR(pdev, "No msix vector for device config\n");
+               goto err;
+       }
+
+       return 0;
+err:
+       ifcvf_free_irq(adapter);
+
+       return -EFAULT;
+
+}
+
+static int ifcvf_request_vq_irq(struct ifcvf_adapter *adapter)
+{
+       struct ifcvf_hw *vf = &adapter->vf;
+       int ret;
+
+       if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG)
+               ret = ifcvf_request_per_vq_irq(adapter);
+       else
+               ret = ifcvf_request_vqs_reused_irq(adapter);
+
+       return ret;
+}
+
+static int ifcvf_request_config_irq(struct ifcvf_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       struct ifcvf_hw *vf = &adapter->vf;
+       int config_vector, ret;
+
+       if (vf->msix_vector_status == MSIX_VECTOR_DEV_SHARED)
+               return 0;
+
+       if (vf->msix_vector_status == MSIX_VECTOR_PER_VQ_AND_CONFIG)
+               /* vector 0 ~ vf->nr_vring for vqs, num vf->nr_vring vector for config interrupt */
+               config_vector = vf->nr_vring;
+
+       if (vf->msix_vector_status ==  MSIX_VECTOR_SHARED_VQ_AND_CONFIG)
+               /* vector 0 for vqs and 1 for config interrupt */
+               config_vector = 1;
 
        snprintf(vf->config_msix_name, 256, "ifcvf[%s]-config\n",
                 pci_name(pdev));
-       vector = 0;
-       vf->config_irq = pci_irq_vector(pdev, vector);
+       vf->config_irq = pci_irq_vector(pdev, config_vector);
        ret = devm_request_irq(&pdev->dev, vf->config_irq,
                               ifcvf_config_changed, 0,
                               vf->config_msix_name, vf);
        if (ret) {
                IFCVF_ERR(pdev, "Failed to request config irq\n");
-               return ret;
+               goto err;
        }
 
-       for (i = 0; i < vf->nr_vring; i++) {
-               snprintf(vf->vring[i].msix_name, 256, "ifcvf[%s]-%d\n",
-                        pci_name(pdev), i);
-               vector = i + IFCVF_MSI_QUEUE_OFF;
-               irq = pci_irq_vector(pdev, vector);
-               ret = devm_request_irq(&pdev->dev, irq,
-                                      ifcvf_intr_handler, 0,
-                                      vf->vring[i].msix_name,
-                                      &vf->vring[i]);
-               if (ret) {
-                       IFCVF_ERR(pdev,
-                                 "Failed to request irq for vq %d\n", i);
-                       ifcvf_free_irq(adapter, i);
+       ret = ifcvf_set_config_vector(vf, config_vector);
+       if (ret == VIRTIO_MSI_NO_VECTOR) {
+               IFCVF_ERR(pdev, "No msix vector for device config\n");
+               goto err;
+       }
 
-                       return ret;
-               }
+       return 0;
+err:
+       ifcvf_free_irq(adapter);
 
-               vf->vring[i].irq = irq;
+       return -EFAULT;
+}
+
+static int ifcvf_request_irq(struct ifcvf_adapter *adapter)
+{
+       struct ifcvf_hw *vf = &adapter->vf;
+       int nvectors, ret, max_intr;
+
+       nvectors = ifcvf_alloc_vectors(adapter);
+       if (nvectors <= 0)
+               return -EFAULT;
+
+       vf->msix_vector_status = MSIX_VECTOR_PER_VQ_AND_CONFIG;
+       max_intr = vf->nr_vring + 1;
+       if (nvectors < max_intr)
+               vf->msix_vector_status = MSIX_VECTOR_SHARED_VQ_AND_CONFIG;
+
+       if (nvectors == 1) {
+               vf->msix_vector_status = MSIX_VECTOR_DEV_SHARED;
+               ret = ifcvf_request_dev_irq(adapter);
+
+               return ret;
        }
 
+       ret = ifcvf_request_vq_irq(adapter);
+       if (ret)
+               return ret;
+
+       ret = ifcvf_request_config_irq(adapter);
+
+       if (ret)
+               return ret;
+
        return 0;
 }
 
 
        if (status_old & VIRTIO_CONFIG_S_DRIVER_OK) {
                ifcvf_stop_datapath(adapter);
-               ifcvf_free_irq(adapter, vf->nr_vring);
+               ifcvf_free_irq(adapter);
        }
 
        ifcvf_reset_vring(adapter);
 {
        struct ifcvf_hw *vf = vdpa_to_vf(vdpa_dev);
 
-       return vf->vring[qid].irq;
+       if (vf->vqs_reused_irq < 0)
+               return vf->vring[qid].irq;
+       else
+               return -EINVAL;
 }
 
 static struct vdpa_notification_area ifcvf_get_vq_notification(struct vdpa_device *vdpa_dev,