aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYu Zhao <yu.zhao@intel.com>2009-05-18 01:51:32 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-05-18 06:25:54 -0400
commit302b4215daa0a704c843da40fd2529e5757a72da (patch)
tree1bc40108fceafd3fbc9faee38c971fa94d560b13
parentdd7264355a203c3456dbba04db471947d3b55e7e (diff)
PCI: support the ATS capability
The PCIe ATS capability makes the Endpoint be able to request the DMA address translation from the IOMMU and cache the translation in the device side, thus alleviate IOMMU pressure and improve the hardware performance in the I/O virtualization environment. 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>
-rw-r--r--drivers/pci/iov.c105
-rw-r--r--drivers/pci/pci.h37
-rw-r--r--include/linux/pci.h2
-rw-r--r--include/linux/pci_regs.h10
4 files changed, 154 insertions, 0 deletions
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index b497daab3d4a..0a7a1b40286f 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -5,6 +5,7 @@
5 * 5 *
6 * PCI Express I/O Virtualization (IOV) support. 6 * PCI Express I/O Virtualization (IOV) support.
7 * Single Root IOV 1.0 7 * Single Root IOV 1.0
8 * Address Translation Service 1.0
8 */ 9 */
9 10
10#include <linux/pci.h> 11#include <linux/pci.h>
@@ -679,3 +680,107 @@ irqreturn_t pci_sriov_migration(struct pci_dev *dev)
679 return sriov_migration(dev) ? IRQ_HANDLED : IRQ_NONE; 680 return sriov_migration(dev) ? IRQ_HANDLED : IRQ_NONE;
680} 681}
681EXPORT_SYMBOL_GPL(pci_sriov_migration); 682EXPORT_SYMBOL_GPL(pci_sriov_migration);
683
684static int ats_alloc_one(struct pci_dev *dev, int ps)
685{
686 int pos;
687 u16 cap;
688 struct pci_ats *ats;
689
690 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
691 if (!pos)
692 return -ENODEV;
693
694 ats = kzalloc(sizeof(*ats), GFP_KERNEL);
695 if (!ats)
696 return -ENOMEM;
697
698 ats->pos = pos;
699 ats->stu = ps;
700 pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
701 ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
702 PCI_ATS_MAX_QDEP;
703 dev->ats = ats;
704
705 return 0;
706}
707
708static void ats_free_one(struct pci_dev *dev)
709{
710 kfree(dev->ats);
711 dev->ats = NULL;
712}
713
714/**
715 * pci_enable_ats - enable the ATS capability
716 * @dev: the PCI device
717 * @ps: the IOMMU page shift
718 *
719 * Returns 0 on success, or negative on failure.
720 */
721int pci_enable_ats(struct pci_dev *dev, int ps)
722{
723 int rc;
724 u16 ctrl;
725
726 BUG_ON(dev->ats);
727
728 if (ps < PCI_ATS_MIN_STU)
729 return -EINVAL;
730
731 rc = ats_alloc_one(dev, ps);
732 if (rc)
733 return rc;
734
735 ctrl = PCI_ATS_CTRL_ENABLE;
736 ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU);
737 pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
738
739 return 0;
740}
741
742/**
743 * pci_disable_ats - disable the ATS capability
744 * @dev: the PCI device
745 */
746void pci_disable_ats(struct pci_dev *dev)
747{
748 u16 ctrl;
749
750 BUG_ON(!dev->ats);
751
752 pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl);
753 ctrl &= ~PCI_ATS_CTRL_ENABLE;
754 pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl);
755
756 ats_free_one(dev);
757}
758
759/**
760 * pci_ats_queue_depth - query the ATS Invalidate Queue Depth
761 * @dev: the PCI device
762 *
763 * Returns the queue depth on success, or negative on failure.
764 *
765 * The ATS spec uses 0 in the Invalidate Queue Depth field to
766 * indicate that the function can accept 32 Invalidate Request.
767 * But here we use the `real' values (i.e. 1~32) for the Queue
768 * Depth.
769 */
770int pci_ats_queue_depth(struct pci_dev *dev)
771{
772 int pos;
773 u16 cap;
774
775 if (dev->ats)
776 return dev->ats->qdep;
777
778 pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS);
779 if (!pos)
780 return -ENODEV;
781
782 pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap);
783
784 return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) :
785 PCI_ATS_MAX_QDEP;
786}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index d03f6b99f292..3c2ec64f78e9 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -229,6 +229,13 @@ struct pci_sriov {
229 u8 __iomem *mstate; /* VF Migration State Array */ 229 u8 __iomem *mstate; /* VF Migration State Array */
230}; 230};
231 231
232/* Address Translation Service */
233struct pci_ats {
234 int pos; /* capability position */
235 int stu; /* Smallest Translation Unit */
236 int qdep; /* Invalidate Queue Depth */
237};
238
232#ifdef CONFIG_PCI_IOV 239#ifdef CONFIG_PCI_IOV
233extern int pci_iov_init(struct pci_dev *dev); 240extern int pci_iov_init(struct pci_dev *dev);
234extern void pci_iov_release(struct pci_dev *dev); 241extern void pci_iov_release(struct pci_dev *dev);
@@ -236,6 +243,20 @@ extern int pci_iov_resource_bar(struct pci_dev *dev, int resno,
236 enum pci_bar_type *type); 243 enum pci_bar_type *type);
237extern void pci_restore_iov_state(struct pci_dev *dev); 244extern void pci_restore_iov_state(struct pci_dev *dev);
238extern int pci_iov_bus_range(struct pci_bus *bus); 245extern int pci_iov_bus_range(struct pci_bus *bus);
246
247extern int pci_enable_ats(struct pci_dev *dev, int ps);
248extern void pci_disable_ats(struct pci_dev *dev);
249extern int pci_ats_queue_depth(struct pci_dev *dev);
250/**
251 * pci_ats_enabled - query the ATS status
252 * @dev: the PCI device
253 *
254 * Returns 1 if ATS capability is enabled, or 0 if not.
255 */
256static inline int pci_ats_enabled(struct pci_dev *dev)
257{
258 return !!dev->ats;
259}
239#else 260#else
240static inline int pci_iov_init(struct pci_dev *dev) 261static inline int pci_iov_init(struct pci_dev *dev)
241{ 262{
@@ -257,6 +278,22 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
257{ 278{
258 return 0; 279 return 0;
259} 280}
281
282static inline int pci_enable_ats(struct pci_dev *dev, int ps)
283{
284 return -ENODEV;
285}
286static inline void pci_disable_ats(struct pci_dev *dev)
287{
288}
289static inline int pci_ats_queue_depth(struct pci_dev *dev)
290{
291 return -ENODEV;
292}
293static inline int pci_ats_enabled(struct pci_dev *dev)
294{
295 return 0;
296}
260#endif /* CONFIG_PCI_IOV */ 297#endif /* CONFIG_PCI_IOV */
261 298
262#endif /* DRIVERS_PCI_H */ 299#endif /* DRIVERS_PCI_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 72698d89e767..bd3e4a798c43 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -188,6 +188,7 @@ struct pci_cap_saved_state {
188struct pcie_link_state; 188struct pcie_link_state;
189struct pci_vpd; 189struct pci_vpd;
190struct pci_sriov; 190struct pci_sriov;
191struct pci_ats;
191 192
192/* 193/*
193 * The pci_dev structure is used to describe PCI devices. 194 * The pci_dev structure is used to describe PCI devices.
@@ -285,6 +286,7 @@ struct pci_dev {
285 struct pci_sriov *sriov; /* SR-IOV capability related */ 286 struct pci_sriov *sriov; /* SR-IOV capability related */
286 struct pci_dev *physfn; /* the PF this VF is associated with */ 287 struct pci_dev *physfn; /* the PF this VF is associated with */
287 }; 288 };
289 struct pci_ats *ats; /* Address Translation Service */
288#endif 290#endif
289}; 291};
290 292
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index e4d08c1b2e0b..c03189c56c7a 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -501,6 +501,7 @@
501#define PCI_EXT_CAP_ID_DSN 3 501#define PCI_EXT_CAP_ID_DSN 3
502#define PCI_EXT_CAP_ID_PWR 4 502#define PCI_EXT_CAP_ID_PWR 4
503#define PCI_EXT_CAP_ID_ARI 14 503#define PCI_EXT_CAP_ID_ARI 14
504#define PCI_EXT_CAP_ID_ATS 15
504#define PCI_EXT_CAP_ID_SRIOV 16 505#define PCI_EXT_CAP_ID_SRIOV 16
505 506
506/* Advanced Error Reporting */ 507/* Advanced Error Reporting */
@@ -619,6 +620,15 @@
619#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */ 620#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */
620#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ 621#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */
621 622
623/* Address Translation Service */
624#define PCI_ATS_CAP 0x04 /* ATS Capability Register */
625#define PCI_ATS_CAP_QDEP(x) ((x) & 0x1f) /* Invalidate Queue Depth */
626#define PCI_ATS_MAX_QDEP 32 /* Max Invalidate Queue Depth */
627#define PCI_ATS_CTRL 0x06 /* ATS Control Register */
628#define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */
629#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */
630#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */
631
622/* Single Root I/O Virtualization */ 632/* Single Root I/O Virtualization */
623#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ 633#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */
624#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ 634#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */