diff options
-rw-r--r-- | drivers/pci/iov.c | 105 | ||||
-rw-r--r-- | drivers/pci/pci.h | 37 | ||||
-rw-r--r-- | include/linux/pci.h | 2 | ||||
-rw-r--r-- | include/linux/pci_regs.h | 10 |
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 | } |
681 | EXPORT_SYMBOL_GPL(pci_sriov_migration); | 682 | EXPORT_SYMBOL_GPL(pci_sriov_migration); |
683 | |||
684 | static 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 | |||
708 | static 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 | */ | ||
721 | int 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 | */ | ||
746 | void 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 | */ | ||
770 | int 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 */ | ||
233 | struct 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 |
233 | extern int pci_iov_init(struct pci_dev *dev); | 240 | extern int pci_iov_init(struct pci_dev *dev); |
234 | extern void pci_iov_release(struct pci_dev *dev); | 241 | extern 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); |
237 | extern void pci_restore_iov_state(struct pci_dev *dev); | 244 | extern void pci_restore_iov_state(struct pci_dev *dev); |
238 | extern int pci_iov_bus_range(struct pci_bus *bus); | 245 | extern int pci_iov_bus_range(struct pci_bus *bus); |
246 | |||
247 | extern int pci_enable_ats(struct pci_dev *dev, int ps); | ||
248 | extern void pci_disable_ats(struct pci_dev *dev); | ||
249 | extern 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 | */ | ||
256 | static inline int pci_ats_enabled(struct pci_dev *dev) | ||
257 | { | ||
258 | return !!dev->ats; | ||
259 | } | ||
239 | #else | 260 | #else |
240 | static inline int pci_iov_init(struct pci_dev *dev) | 261 | static 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 | |||
282 | static inline int pci_enable_ats(struct pci_dev *dev, int ps) | ||
283 | { | ||
284 | return -ENODEV; | ||
285 | } | ||
286 | static inline void pci_disable_ats(struct pci_dev *dev) | ||
287 | { | ||
288 | } | ||
289 | static inline int pci_ats_queue_depth(struct pci_dev *dev) | ||
290 | { | ||
291 | return -ENODEV; | ||
292 | } | ||
293 | static 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 { | |||
188 | struct pcie_link_state; | 188 | struct pcie_link_state; |
189 | struct pci_vpd; | 189 | struct pci_vpd; |
190 | struct pci_sriov; | 190 | struct pci_sriov; |
191 | struct 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 */ |