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