diff options
| -rw-r--r-- | drivers/pci/iov.c | 66 | ||||
| -rw-r--r-- | drivers/pci/pci.h | 4 |
2 files changed, 55 insertions, 15 deletions
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 0a7a1b40286f..415140499ffb 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c | |||
| @@ -491,10 +491,10 @@ found: | |||
| 491 | 491 | ||
| 492 | if (pdev) | 492 | if (pdev) |
| 493 | iov->dev = pci_dev_get(pdev); | 493 | iov->dev = pci_dev_get(pdev); |
| 494 | else { | 494 | else |
| 495 | iov->dev = dev; | 495 | iov->dev = dev; |
| 496 | mutex_init(&iov->lock); | 496 | |
| 497 | } | 497 | mutex_init(&iov->lock); |
| 498 | 498 | ||
| 499 | dev->sriov = iov; | 499 | dev->sriov = iov; |
| 500 | dev->is_physfn = 1; | 500 | dev->is_physfn = 1; |
| @@ -514,11 +514,11 @@ static void sriov_release(struct pci_dev *dev) | |||
| 514 | { | 514 | { |
| 515 | BUG_ON(dev->sriov->nr_virtfn); | 515 | BUG_ON(dev->sriov->nr_virtfn); |
| 516 | 516 | ||
| 517 | if (dev == dev->sriov->dev) | 517 | if (dev != dev->sriov->dev) |
| 518 | mutex_destroy(&dev->sriov->lock); | ||
| 519 | else | ||
| 520 | pci_dev_put(dev->sriov->dev); | 518 | pci_dev_put(dev->sriov->dev); |
| 521 | 519 | ||
| 520 | mutex_destroy(&dev->sriov->lock); | ||
| 521 | |||
| 522 | kfree(dev->sriov); | 522 | kfree(dev->sriov); |
| 523 | dev->sriov = NULL; | 523 | dev->sriov = NULL; |
| 524 | } | 524 | } |
| @@ -723,19 +723,40 @@ int pci_enable_ats(struct pci_dev *dev, int ps) | |||
| 723 | int rc; | 723 | int rc; |
| 724 | u16 ctrl; | 724 | u16 ctrl; |
| 725 | 725 | ||
| 726 | BUG_ON(dev->ats); | 726 | BUG_ON(dev->ats && dev->ats->is_enabled); |
| 727 | 727 | ||
| 728 | if (ps < PCI_ATS_MIN_STU) | 728 | if (ps < PCI_ATS_MIN_STU) |
| 729 | return -EINVAL; | 729 | return -EINVAL; |
| 730 | 730 | ||
| 731 | rc = ats_alloc_one(dev, ps); | 731 | if (dev->is_physfn || dev->is_virtfn) { |
| 732 | if (rc) | 732 | struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn; |
| 733 | return rc; | 733 | |
| 734 | mutex_lock(&pdev->sriov->lock); | ||
| 735 | if (pdev->ats) | ||
| 736 | rc = pdev->ats->stu == ps ? 0 : -EINVAL; | ||
| 737 | else | ||
| 738 | rc = ats_alloc_one(pdev, ps); | ||
| 739 | |||
| 740 | if (!rc) | ||
| 741 | pdev->ats->ref_cnt++; | ||
| 742 | mutex_unlock(&pdev->sriov->lock); | ||
| 743 | if (rc) | ||
| 744 | return rc; | ||
| 745 | } | ||
| 746 | |||
| 747 | if (!dev->is_physfn) { | ||
| 748 | rc = ats_alloc_one(dev, ps); | ||
| 749 | if (rc) | ||
| 750 | return rc; | ||
| 751 | } | ||
| 734 | 752 | ||
| 735 | ctrl = PCI_ATS_CTRL_ENABLE; | 753 | ctrl = PCI_ATS_CTRL_ENABLE; |
| 736 | ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU); | 754 | if (!dev->is_virtfn) |
| 755 | ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU); | ||
| 737 | pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); | 756 | pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); |
| 738 | 757 | ||
| 758 | dev->ats->is_enabled = 1; | ||
| 759 | |||
| 739 | return 0; | 760 | return 0; |
| 740 | } | 761 | } |
| 741 | 762 | ||
| @@ -747,13 +768,26 @@ void pci_disable_ats(struct pci_dev *dev) | |||
| 747 | { | 768 | { |
| 748 | u16 ctrl; | 769 | u16 ctrl; |
| 749 | 770 | ||
| 750 | BUG_ON(!dev->ats); | 771 | BUG_ON(!dev->ats || !dev->ats->is_enabled); |
| 751 | 772 | ||
| 752 | pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl); | 773 | pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl); |
| 753 | ctrl &= ~PCI_ATS_CTRL_ENABLE; | 774 | ctrl &= ~PCI_ATS_CTRL_ENABLE; |
| 754 | pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); | 775 | pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); |
| 755 | 776 | ||
| 756 | ats_free_one(dev); | 777 | dev->ats->is_enabled = 0; |
| 778 | |||
| 779 | if (dev->is_physfn || dev->is_virtfn) { | ||
| 780 | struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn; | ||
| 781 | |||
| 782 | mutex_lock(&pdev->sriov->lock); | ||
| 783 | pdev->ats->ref_cnt--; | ||
| 784 | if (!pdev->ats->ref_cnt) | ||
| 785 | ats_free_one(pdev); | ||
| 786 | mutex_unlock(&pdev->sriov->lock); | ||
| 787 | } | ||
| 788 | |||
| 789 | if (!dev->is_physfn) | ||
| 790 | ats_free_one(dev); | ||
| 757 | } | 791 | } |
| 758 | 792 | ||
| 759 | /** | 793 | /** |
| @@ -765,13 +799,17 @@ void pci_disable_ats(struct pci_dev *dev) | |||
| 765 | * The ATS spec uses 0 in the Invalidate Queue Depth field to | 799 | * The ATS spec uses 0 in the Invalidate Queue Depth field to |
| 766 | * indicate that the function can accept 32 Invalidate Request. | 800 | * indicate that the function can accept 32 Invalidate Request. |
| 767 | * But here we use the `real' values (i.e. 1~32) for the Queue | 801 | * But here we use the `real' values (i.e. 1~32) for the Queue |
| 768 | * Depth. | 802 | * Depth; and 0 indicates the function shares the Queue with |
| 803 | * other functions (doesn't exclusively own a Queue). | ||
| 769 | */ | 804 | */ |
| 770 | int pci_ats_queue_depth(struct pci_dev *dev) | 805 | int pci_ats_queue_depth(struct pci_dev *dev) |
| 771 | { | 806 | { |
| 772 | int pos; | 807 | int pos; |
| 773 | u16 cap; | 808 | u16 cap; |
| 774 | 809 | ||
| 810 | if (dev->is_virtfn) | ||
| 811 | return 0; | ||
| 812 | |||
| 775 | if (dev->ats) | 813 | if (dev->ats) |
| 776 | return dev->ats->qdep; | 814 | return dev->ats->qdep; |
| 777 | 815 | ||
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 3c2ec64f78e9..f73bcbedf37c 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h | |||
| @@ -234,6 +234,8 @@ struct pci_ats { | |||
| 234 | int pos; /* capability position */ | 234 | int pos; /* capability position */ |
| 235 | int stu; /* Smallest Translation Unit */ | 235 | int stu; /* Smallest Translation Unit */ |
| 236 | int qdep; /* Invalidate Queue Depth */ | 236 | int qdep; /* Invalidate Queue Depth */ |
| 237 | int ref_cnt; /* Physical Function reference count */ | ||
| 238 | int is_enabled:1; /* Enable bit is set */ | ||
| 237 | }; | 239 | }; |
| 238 | 240 | ||
| 239 | #ifdef CONFIG_PCI_IOV | 241 | #ifdef CONFIG_PCI_IOV |
| @@ -255,7 +257,7 @@ extern int pci_ats_queue_depth(struct pci_dev *dev); | |||
| 255 | */ | 257 | */ |
| 256 | static inline int pci_ats_enabled(struct pci_dev *dev) | 258 | static inline int pci_ats_enabled(struct pci_dev *dev) |
| 257 | { | 259 | { |
| 258 | return !!dev->ats; | 260 | return dev->ats && dev->ats->is_enabled; |
| 259 | } | 261 | } |
| 260 | #else | 262 | #else |
| 261 | static inline int pci_iov_init(struct pci_dev *dev) | 263 | static inline int pci_iov_init(struct pci_dev *dev) |
