aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoerg Roedel <joerg.roedel@amd.com>2011-09-27 09:57:13 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-10-14 12:05:33 -0400
commitdb3c33c6d3fa04ee46b491e9d75d0d3b4798d074 (patch)
tree6c1031398621e1b7195b2b23b7045a2eb5e917e1
parent78d090b0be3f072a3c95022771c35183af961aaa (diff)
PCI: Move ATS implementation into own file
ATS does not depend on IOV support, so move the code into its own file. This file will also include support for the PRI and PASID capabilities later. Also give ATS its own Kconfig variable to allow selecting it without IOV support. Reviewed-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
-rw-r--r--drivers/pci/Kconfig4
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/pci/ats.c155
-rw-r--r--drivers/pci/iov.c142
-rw-r--r--include/linux/pci-ats.h2
5 files changed, 162 insertions, 142 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 0fa466a91bf..1d8ce839586 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -71,9 +71,13 @@ config HT_IRQ
71 71
72 If unsure say Y. 72 If unsure say Y.
73 73
74config PCI_ATS
75 bool
76
74config PCI_IOV 77config PCI_IOV
75 bool "PCI IOV support" 78 bool "PCI IOV support"
76 depends on PCI 79 depends on PCI
80 select PCI_ATS
77 help 81 help
78 I/O Virtualization is a PCI feature supported by some devices 82 I/O Virtualization is a PCI feature supported by some devices
79 which allows them to create virtual devices which share their 83 which allows them to create virtual devices which share their
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 6fadae3ad13..083a49fee56 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PCI_MSI) += msi.o
29# Build the Hypertransport interrupt support 29# Build the Hypertransport interrupt support
30obj-$(CONFIG_HT_IRQ) += htirq.o 30obj-$(CONFIG_HT_IRQ) += htirq.o
31 31
32obj-$(CONFIG_PCI_ATS) += ats.o
32obj-$(CONFIG_PCI_IOV) += iov.o 33obj-$(CONFIG_PCI_IOV) += iov.o
33 34
34# 35#
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
new file mode 100644
index 00000000000..ae4bf87afb0
--- /dev/null
+++ b/drivers/pci/ats.c
@@ -0,0 +1,155 @@
1/*
2 * drivers/pci/ats.c
3 *
4 * Copyright (C) 2009 Intel Corporation, Yu Zhao <yu.zhao@intel.com>
5 *
6 * PCI Express I/O Virtualization (IOV) support.
7 * Address Translation Service 1.0
8 */
9
10#include <linux/pci-ats.h>
11#include <linux/pci.h>
12
13#include "pci.h"
14
15static int ats_alloc_one(struct pci_dev *dev, int ps)
16{
17 int pos;
18 u16 cap;
19 struct pci_ats *ats;
20
21 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
22 if (!pos)
23 return -ENODEV;
24
25 ats = kzalloc(sizeof(*ats), GFP_KERNEL);
26 if (!ats)
27 return -ENOMEM;
28
29 ats->pos = pos;
30 ats->stu = ps;
31 pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
32 ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
33 PCI_ATS_MAX_QDEP;
34 dev->ats = ats;
35
36 return 0;
37}
38
39static void ats_free_one(struct pci_dev *dev)
40{
41 kfree(dev->ats);
42 dev->ats = NULL;
43}
44
45/**
46 * pci_enable_ats - enable the ATS capability
47 * @dev: the PCI device
48 * @ps: the IOMMU page shift
49 *
50 * Returns 0 on success, or negative on failure.
51 */
52int pci_enable_ats(struct pci_dev *dev, int ps)
53{
54 int rc;
55 u16 ctrl;
56
57 BUG_ON(dev->ats && dev->ats->is_enabled);
58
59 if (ps < PCI_ATS_MIN_STU)
60 return -EINVAL;
61
62 if (dev->is_physfn || dev->is_virtfn) {
63 struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
64
65 mutex_lock(&pdev->sriov->lock);
66 if (pdev->ats)
67 rc = pdev->ats->stu == ps ? 0 : -EINVAL;
68 else
69 rc = ats_alloc_one(pdev, ps);
70
71 if (!rc)
72 pdev->ats->ref_cnt++;
73 mutex_unlock(&pdev->sriov->lock);
74 if (rc)
75 return rc;
76 }
77
78 if (!dev->is_physfn) {
79 rc = ats_alloc_one(dev, ps);
80 if (rc)
81 return rc;
82 }
83
84 ctrl = PCI_ATS_CTRL_ENABLE;
85 if (!dev->is_virtfn)
86 ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU);
87 pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
88
89 dev->ats->is_enabled = 1;
90
91 return 0;
92}
93
94/**
95 * pci_disable_ats - disable the ATS capability
96 * @dev: the PCI device
97 */
98void pci_disable_ats(struct pci_dev *dev)
99{
100 u16 ctrl;
101
102 BUG_ON(!dev->ats || !dev->ats->is_enabled);
103
104 pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
105 ctrl &= ~PCI_ATS_CTRL_ENABLE;
106 pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
107
108 dev->ats->is_enabled = 0;
109
110 if (dev->is_physfn || dev->is_virtfn) {
111 struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
112
113 mutex_lock(&pdev->sriov->lock);
114 pdev->ats->ref_cnt--;
115 if (!pdev->ats->ref_cnt)
116 ats_free_one(pdev);
117 mutex_unlock(&pdev->sriov->lock);
118 }
119
120 if (!dev->is_physfn)
121 ats_free_one(dev);
122}
123
124/**
125 * pci_ats_queue_depth - query the ATS Invalidate Queue Depth
126 * @dev: the PCI device
127 *
128 * Returns the queue depth on success, or negative on failure.
129 *
130 * The ATS spec uses 0 in the Invalidate Queue Depth field to
131 * indicate that the function can accept 32 Invalidate Request.
132 * But here we use the `real' values (i.e. 1~32) for the Queue
133 * Depth; and 0 indicates the function shares the Queue with
134 * other functions (doesn't exclusively own a Queue).
135 */
136int pci_ats_queue_depth(struct pci_dev *dev)
137{
138 int pos;
139 u16 cap;
140
141 if (dev->is_virtfn)
142 return 0;
143
144 if (dev->ats)
145 return dev->ats->qdep;
146
147 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
148 if (!pos)
149 return -ENODEV;
150
151 pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
152
153 return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
154 PCI_ATS_MAX_QDEP;
155}
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 42fae477651..9b4e88c636f 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -722,145 +722,3 @@ int pci_num_vf(struct pci_dev *dev)
722 return dev->sriov->nr_virtfn; 722 return dev->sriov->nr_virtfn;
723} 723}
724EXPORT_SYMBOL_GPL(pci_num_vf); 724EXPORT_SYMBOL_GPL(pci_num_vf);
725
726static int ats_alloc_one(struct pci_dev *dev, int ps)
727{
728 int pos;
729 u16 cap;
730 struct pci_ats *ats;
731
732 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
733 if (!pos)
734 return -ENODEV;
735
736 ats = kzalloc(sizeof(*ats), GFP_KERNEL);
737 if (!ats)
738 return -ENOMEM;
739
740 ats->pos = pos;
741 ats->stu = ps;
742 pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
743 ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
744 PCI_ATS_MAX_QDEP;
745 dev->ats = ats;
746
747 return 0;
748}
749
750static void ats_free_one(struct pci_dev *dev)
751{
752 kfree(dev->ats);
753 dev->ats = NULL;
754}
755
756/**
757 * pci_enable_ats - enable the ATS capability
758 * @dev: the PCI device
759 * @ps: the IOMMU page shift
760 *
761 * Returns 0 on success, or negative on failure.
762 */
763int pci_enable_ats(struct pci_dev *dev, int ps)
764{
765 int rc;
766 u16 ctrl;
767
768 BUG_ON(dev->ats && dev->ats->is_enabled);
769
770 if (ps < PCI_ATS_MIN_STU)
771 return -EINVAL;
772
773 if (dev->is_physfn || dev->is_virtfn) {
774 struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
775
776 mutex_lock(&pdev->sriov->lock);
777 if (pdev->ats)
778 rc = pdev->ats->stu == ps ? 0 : -EINVAL;
779 else
780 rc = ats_alloc_one(pdev, ps);
781
782 if (!rc)
783 pdev->ats->ref_cnt++;
784 mutex_unlock(&pdev->sriov->lock);
785 if (rc)
786 return rc;
787 }
788
789 if (!dev->is_physfn) {
790 rc = ats_alloc_one(dev, ps);
791 if (rc)
792 return rc;
793 }
794
795 ctrl = PCI_ATS_CTRL_ENABLE;
796 if (!dev->is_virtfn)
797 ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU);
798 pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
799
800 dev->ats->is_enabled = 1;
801
802 return 0;
803}
804
805/**
806 * pci_disable_ats - disable the ATS capability
807 * @dev: the PCI device
808 */
809void pci_disable_ats(struct pci_dev *dev)
810{
811 u16 ctrl;
812
813 BUG_ON(!dev->ats || !dev->ats->is_enabled);
814
815 pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
816 ctrl &= ~PCI_ATS_CTRL_ENABLE;
817 pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
818
819 dev->ats->is_enabled = 0;
820
821 if (dev->is_physfn || dev->is_virtfn) {
822 struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn;
823
824 mutex_lock(&pdev->sriov->lock);
825 pdev->ats->ref_cnt--;
826 if (!pdev->ats->ref_cnt)
827 ats_free_one(pdev);
828 mutex_unlock(&pdev->sriov->lock);
829 }
830
831 if (!dev->is_physfn)
832 ats_free_one(dev);
833}
834
835/**
836 * pci_ats_queue_depth - query the ATS Invalidate Queue Depth
837 * @dev: the PCI device
838 *
839 * Returns the queue depth on success, or negative on failure.
840 *
841 * The ATS spec uses 0 in the Invalidate Queue Depth field to
842 * indicate that the function can accept 32 Invalidate Request.
843 * But here we use the `real' values (i.e. 1~32) for the Queue
844 * Depth; and 0 indicates the function shares the Queue with
845 * other functions (doesn't exclusively own a Queue).
846 */
847int pci_ats_queue_depth(struct pci_dev *dev)
848{
849 int pos;
850 u16 cap;
851
852 if (dev->is_virtfn)
853 return 0;
854
855 if (dev->ats)
856 return dev->ats->qdep;
857
858 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
859 if (!pos)
860 return -ENODEV;
861
862 pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
863
864 return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
865 PCI_ATS_MAX_QDEP;
866}
diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h
index 655824fa4c7..4eab42bf2af 100644
--- a/include/linux/pci-ats.h
+++ b/include/linux/pci-ats.h
@@ -1,6 +1,8 @@
1#ifndef LINUX_PCI_ATS_H 1#ifndef LINUX_PCI_ATS_H
2#define LINUX_PCI_ATS_H 2#define LINUX_PCI_ATS_H
3 3
4#include <linux/pci.h>
5
4/* Address Translation Service */ 6/* Address Translation Service */
5struct pci_ats { 7struct pci_ats {
6 int pos; /* capability position */ 8 int pos; /* capability position */