diff options
author | Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com> | 2015-12-10 11:55:27 -0500 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2015-12-21 08:49:32 -0500 |
commit | 471036b2b895789c2305428fd879006468e4a758 (patch) | |
tree | afabc515637003b9b21dd69b105e021533869d56 | |
parent | 9f9499ae8e6415cefc4fe0a96ad0e27864353c89 (diff) |
acpi: pci: Setup MSI domain for ACPI based pci devices
This patch introduces pci_msi_register_fwnode_provider() for irqchip
to register a callback, to provide a way to determine appropriate MSI
domain for a pci device.
It also introduces pci_host_bridge_acpi_msi_domain(), which returns
the MSI domain of the specified PCI host bridge with DOMAIN_BUS_PCI_MSI
bus token. Then, it is assigned to pci device.
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Rafael J. Wysocki <rjw@rjwysocki.net>
Signed-off-by: Suravee Suthikulpanit <Suravee.Suthikulpanit@amd.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r-- | drivers/pci/pci-acpi.c | 42 | ||||
-rw-r--r-- | drivers/pci/probe.c | 2 | ||||
-rw-r--r-- | include/linux/irqdomain.h | 5 | ||||
-rw-r--r-- | include/linux/pci.h | 10 |
4 files changed, 59 insertions, 0 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index a32ba753e413..d3f32d6417ef 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c | |||
@@ -9,7 +9,9 @@ | |||
9 | 9 | ||
10 | #include <linux/delay.h> | 10 | #include <linux/delay.h> |
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/irqdomain.h> | ||
12 | #include <linux/pci.h> | 13 | #include <linux/pci.h> |
14 | #include <linux/msi.h> | ||
13 | #include <linux/pci_hotplug.h> | 15 | #include <linux/pci_hotplug.h> |
14 | #include <linux/module.h> | 16 | #include <linux/module.h> |
15 | #include <linux/pci-aspm.h> | 17 | #include <linux/pci-aspm.h> |
@@ -689,6 +691,46 @@ static struct acpi_bus_type acpi_pci_bus = { | |||
689 | .cleanup = pci_acpi_cleanup, | 691 | .cleanup = pci_acpi_cleanup, |
690 | }; | 692 | }; |
691 | 693 | ||
694 | |||
695 | static struct fwnode_handle *(*pci_msi_get_fwnode_cb)(struct device *dev); | ||
696 | |||
697 | /** | ||
698 | * pci_msi_register_fwnode_provider - Register callback to retrieve fwnode | ||
699 | * @fn: Callback matching a device to a fwnode that identifies a PCI | ||
700 | * MSI domain. | ||
701 | * | ||
702 | * This should be called by irqchip driver, which is the parent of | ||
703 | * the MSI domain to provide callback interface to query fwnode. | ||
704 | */ | ||
705 | void | ||
706 | pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *)) | ||
707 | { | ||
708 | pci_msi_get_fwnode_cb = fn; | ||
709 | } | ||
710 | |||
711 | /** | ||
712 | * pci_host_bridge_acpi_msi_domain - Retrieve MSI domain of a PCI host bridge | ||
713 | * @bus: The PCI host bridge bus. | ||
714 | * | ||
715 | * This function uses the callback function registered by | ||
716 | * pci_msi_register_fwnode_provider() to retrieve the irq_domain with | ||
717 | * type DOMAIN_BUS_PCI_MSI of the specified host bridge bus. | ||
718 | * This returns NULL on error or when the domain is not found. | ||
719 | */ | ||
720 | struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) | ||
721 | { | ||
722 | struct fwnode_handle *fwnode; | ||
723 | |||
724 | if (!pci_msi_get_fwnode_cb) | ||
725 | return NULL; | ||
726 | |||
727 | fwnode = pci_msi_get_fwnode_cb(&bus->dev); | ||
728 | if (!fwnode) | ||
729 | return NULL; | ||
730 | |||
731 | return irq_find_matching_fwnode(fwnode, DOMAIN_BUS_PCI_MSI); | ||
732 | } | ||
733 | |||
692 | static int __init acpi_pci_init(void) | 734 | static int __init acpi_pci_init(void) |
693 | { | 735 | { |
694 | int ret; | 736 | int ret; |
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index edb1984201e9..553a029e37f1 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -672,6 +672,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus) | |||
672 | * should be called from here. | 672 | * should be called from here. |
673 | */ | 673 | */ |
674 | d = pci_host_bridge_of_msi_domain(bus); | 674 | d = pci_host_bridge_of_msi_domain(bus); |
675 | if (!d) | ||
676 | d = pci_host_bridge_acpi_msi_domain(bus); | ||
675 | 677 | ||
676 | return d; | 678 | return d; |
677 | } | 679 | } |
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h index d5e5c5bef28c..a06fedacd955 100644 --- a/include/linux/irqdomain.h +++ b/include/linux/irqdomain.h | |||
@@ -410,6 +410,11 @@ static inline bool irq_domain_is_hierarchy(struct irq_domain *domain) | |||
410 | static inline void irq_dispose_mapping(unsigned int virq) { } | 410 | static inline void irq_dispose_mapping(unsigned int virq) { } |
411 | static inline void irq_domain_activate_irq(struct irq_data *data) { } | 411 | static inline void irq_domain_activate_irq(struct irq_data *data) { } |
412 | static inline void irq_domain_deactivate_irq(struct irq_data *data) { } | 412 | static inline void irq_domain_deactivate_irq(struct irq_data *data) { } |
413 | static inline struct irq_domain *irq_find_matching_fwnode( | ||
414 | struct fwnode_handle *fwnode, enum irq_domain_bus_token bus_token) | ||
415 | { | ||
416 | return NULL; | ||
417 | } | ||
413 | #endif /* !CONFIG_IRQ_DOMAIN */ | 418 | #endif /* !CONFIG_IRQ_DOMAIN */ |
414 | 419 | ||
415 | #endif /* _LINUX_IRQDOMAIN_H */ | 420 | #endif /* _LINUX_IRQDOMAIN_H */ |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 6ae25aae88fd..d86378c226fb 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -1946,6 +1946,16 @@ static inline struct irq_domain * | |||
1946 | pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; } | 1946 | pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; } |
1947 | #endif /* CONFIG_OF */ | 1947 | #endif /* CONFIG_OF */ |
1948 | 1948 | ||
1949 | #ifdef CONFIG_ACPI | ||
1950 | struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus); | ||
1951 | |||
1952 | void | ||
1953 | pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *)); | ||
1954 | #else | ||
1955 | static inline struct irq_domain * | ||
1956 | pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; } | ||
1957 | #endif | ||
1958 | |||
1949 | #ifdef CONFIG_EEH | 1959 | #ifdef CONFIG_EEH |
1950 | static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev) | 1960 | static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev) |
1951 | { | 1961 | { |