diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/iov.c | 105 | ||||
-rw-r--r-- | drivers/pci/pci.h | 37 |
2 files changed, 142 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 */ |