diff options
author | Yu Zhao <yu.zhao@intel.com> | 2009-05-18 01:51:33 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-05-18 06:25:58 -0400 |
commit | e277d2fc79d6abb86fafadb58dca0b9c498a9aa7 (patch) | |
tree | 6f7a6c5bf2b300bec9fa76266eeb9089dc82e651 /drivers/pci | |
parent | 302b4215daa0a704c843da40fd2529e5757a72da (diff) |
PCI: handle Virtual Function ATS enabling
The SR-IOV spec requires that the Smallest Translation Unit and
the Invalidate Queue Depth fields in the Virtual Function ATS
capability are hardwired to 0. If a function is a Virtual Function,
then and set its Physical Function's STU before enabling the ATS.
Signed-off-by: Yu Zhao <yu.zhao@intel.com>
Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/pci')
-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) |