aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorYu Zhao <yu.zhao@intel.com>2009-05-18 01:51:33 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-05-18 06:25:58 -0400
commite277d2fc79d6abb86fafadb58dca0b9c498a9aa7 (patch)
tree6f7a6c5bf2b300bec9fa76266eeb9089dc82e651 /drivers/pci
parent302b4215daa0a704c843da40fd2529e5757a72da (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.c66
-rw-r--r--drivers/pci/pci.h4
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 */
770int pci_ats_queue_depth(struct pci_dev *dev) 805int 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 */
256static inline int pci_ats_enabled(struct pci_dev *dev) 258static 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
261static inline int pci_iov_init(struct pci_dev *dev) 263static inline int pci_iov_init(struct pci_dev *dev)