diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-04 01:40:01 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-11-04 01:40:01 +0300 |
commit | 6aa2fdb87cf01d7746955c600cbac352dc04d451 (patch) | |
tree | 75ba04b2579fafb103dfa049289e7e6b7b3d5bb9 /drivers/pci | |
parent | 7b2a4306f9e7d64bb408a6df3bb419500578068a (diff) | |
parent | d9e4ad5badf4ccbfddee208c898fb8fd0c8836b1 (diff) | |
download | linux-6aa2fdb87cf01d7746955c600cbac352dc04d451.tar.xz |
Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull irq updates from Thomas Gleixner:
"The irq departement delivers:
- Rework the irqdomain core infrastructure to accomodate ACPI based
systems. This is required to support ARM64 without creating
artificial device tree nodes.
- Sanitize the ACPI based ARM GIC initialization by making use of the
new firmware independent irqdomain core
- Further improvements to the generic MSI management
- Generalize the irq migration on CPU hotplug
- Improvements to the threaded interrupt infrastructure
- Allow the migration of "chained" low level interrupt handlers
- Allow optional force masking of interrupts in disable_irq[_nosysnc]
- Support for two new interrupt chips - Sigh!
- A larger set of errata fixes for ARM gicv3
- The usual pile of fixes, updates, improvements and cleanups all
over the place"
* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (71 commits)
Document that IRQ_NONE should be returned when IRQ not actually handled
PCI/MSI: Allow the MSI domain to be device-specific
PCI: Add per-device MSI domain hook
of/irq: Use the msi-map property to provide device-specific MSI domain
of/irq: Split of_msi_map_rid to reuse msi-map lookup
irqchip/gic-v3-its: Parse new version of msi-parent property
PCI/MSI: Use of_msi_get_domain instead of open-coded "msi-parent" parsing
of/irq: Use of_msi_get_domain instead of open-coded "msi-parent" parsing
of/irq: Add support code for multi-parent version of "msi-parent"
irqchip/gic-v3-its: Add handling of PCI requester id.
PCI/MSI: Add helper function pci_msi_domain_get_msi_rid().
of/irq: Add new function of_msi_map_rid()
Docs: dt: Add PCI MSI map bindings
irqchip/gic-v2m: Add support for multiple MSI frames
irqchip/gic-v3: Fix translation of LPIs after conversion to irq_fwspec
irqchip/mxs: Add Alphascale ASM9260 support
irqchip/mxs: Prepare driver for hardware with different offsets
irqchip/mxs: Panic if ioremap or domain creation fails
irqdomain: Documentation updates
irqdomain/msi: Use fwnode instead of of_node
...
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/host/pci-xgene-msi.c | 2 | ||||
-rw-r--r-- | drivers/pci/msi.c | 63 | ||||
-rw-r--r-- | drivers/pci/of.c | 13 | ||||
-rw-r--r-- | drivers/pci/probe.c | 43 |
4 files changed, 101 insertions, 20 deletions
diff --git a/drivers/pci/host/pci-xgene-msi.c b/drivers/pci/host/pci-xgene-msi.c index e491681daf22..a6456b578269 100644 --- a/drivers/pci/host/pci-xgene-msi.c +++ b/drivers/pci/host/pci-xgene-msi.c @@ -256,7 +256,7 @@ static int xgene_allocate_domains(struct xgene_msi *msi) if (!msi->inner_domain) return -ENOMEM; - msi->msi_domain = pci_msi_create_irq_domain(msi->node, + msi->msi_domain = pci_msi_create_irq_domain(of_node_to_fwnode(msi->node), &xgene_msi_domain_info, msi->inner_domain); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 4a7da3c3e035..45a51486d080 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -20,6 +20,7 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/irqdomain.h> +#include <linux/of_irq.h> #include "pci.h" @@ -1250,8 +1251,8 @@ static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info) } /** - * pci_msi_create_irq_domain - Creat a MSI interrupt domain - * @node: Optional device-tree node of the interrupt controller + * pci_msi_create_irq_domain - Create a MSI interrupt domain + * @fwnode: Optional fwnode of the interrupt controller * @info: MSI domain info * @parent: Parent irq domain * @@ -1260,7 +1261,7 @@ static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info) * Returns: * A domain pointer or NULL in case of failure. */ -struct irq_domain *pci_msi_create_irq_domain(struct device_node *node, +struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode, struct msi_domain_info *info, struct irq_domain *parent) { @@ -1271,7 +1272,7 @@ struct irq_domain *pci_msi_create_irq_domain(struct device_node *node, if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS) pci_msi_domain_update_chip_ops(info); - domain = msi_create_irq_domain(node, info, parent); + domain = msi_create_irq_domain(fwnode, info, parent); if (!domain) return NULL; @@ -1307,14 +1308,14 @@ void pci_msi_domain_free_irqs(struct irq_domain *domain, struct pci_dev *dev) /** * pci_msi_create_default_irq_domain - Create a default MSI interrupt domain - * @node: Optional device-tree node of the interrupt controller + * @fwnode: Optional fwnode of the interrupt controller * @info: MSI domain info * @parent: Parent irq domain * * Returns: A domain pointer or NULL in case of failure. If successful * the default PCI/MSI irqdomain pointer is updated. */ -struct irq_domain *pci_msi_create_default_irq_domain(struct device_node *node, +struct irq_domain *pci_msi_create_default_irq_domain(struct fwnode_handle *fwnode, struct msi_domain_info *info, struct irq_domain *parent) { struct irq_domain *domain; @@ -1324,11 +1325,59 @@ struct irq_domain *pci_msi_create_default_irq_domain(struct device_node *node, pr_err("PCI: default irq domain for PCI MSI has already been created.\n"); domain = NULL; } else { - domain = pci_msi_create_irq_domain(node, info, parent); + domain = pci_msi_create_irq_domain(fwnode, info, parent); pci_msi_default_domain = domain; } mutex_unlock(&pci_msi_domain_lock); return domain; } + +static int get_msi_id_cb(struct pci_dev *pdev, u16 alias, void *data) +{ + u32 *pa = data; + + *pa = alias; + return 0; +} +/** + * pci_msi_domain_get_msi_rid - Get the MSI requester id (RID) + * @domain: The interrupt domain + * @pdev: The PCI device. + * + * The RID for a device is formed from the alias, with a firmware + * supplied mapping applied + * + * Returns: The RID. + */ +u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev) +{ + struct device_node *of_node; + u32 rid = 0; + + pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid); + + of_node = irq_domain_get_of_node(domain); + if (of_node) + rid = of_msi_map_rid(&pdev->dev, of_node, rid); + + return rid; +} + +/** + * pci_msi_get_device_domain - Get the MSI domain for a given PCI device + * @pdev: The PCI device + * + * Use the firmware data to find a device-specific MSI domain + * (i.e. not one that is ste as a default). + * + * Returns: The coresponding MSI domain or NULL if none has been found. + */ +struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev) +{ + u32 rid = 0; + + pci_for_each_dma_alias(pdev, get_msi_id_cb, &rid); + return of_msi_map_get_device_domain(&pdev->dev, rid); +} #endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */ diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 2e99a500cb83..e112da11630e 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/of.h> +#include <linux/of_irq.h> #include <linux/of_pci.h> #include "pci.h" @@ -64,27 +65,25 @@ struct device_node * __weak pcibios_get_phb_of_node(struct pci_bus *bus) struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus) { #ifdef CONFIG_IRQ_DOMAIN - struct device_node *np; struct irq_domain *d; if (!bus->dev.of_node) return NULL; /* Start looking for a phandle to an MSI controller. */ - np = of_parse_phandle(bus->dev.of_node, "msi-parent", 0); + d = of_msi_get_domain(&bus->dev, bus->dev.of_node, DOMAIN_BUS_PCI_MSI); + if (d) + return d; /* * If we don't have an msi-parent property, look for a domain * directly attached to the host bridge. */ - if (!np) - np = bus->dev.of_node; - - d = irq_find_matching_host(np, DOMAIN_BUS_PCI_MSI); + d = irq_find_matching_host(bus->dev.of_node, DOMAIN_BUS_PCI_MSI); if (d) return d; - return irq_find_host(np); + return irq_find_host(bus->dev.of_node); #else return NULL; #endif diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 8361d27e5eca..f14a970b61fa 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1622,15 +1622,48 @@ static void pci_init_capabilities(struct pci_dev *dev) pci_enable_acs(dev); } +/* + * This is the equivalent of pci_host_bridge_msi_domain that acts on + * devices. Firmware interfaces that can select the MSI domain on a + * per-device basis should be called from here. + */ +static struct irq_domain *pci_dev_msi_domain(struct pci_dev *dev) +{ + struct irq_domain *d; + + /* + * If a domain has been set through the pcibios_add_device + * callback, then this is the one (platform code knows best). + */ + d = dev_get_msi_domain(&dev->dev); + if (d) + return d; + + /* + * Let's see if we have a firmware interface able to provide + * the domain. + */ + d = pci_msi_get_device_domain(dev); + if (d) + return d; + + return NULL; +} + static void pci_set_msi_domain(struct pci_dev *dev) { + struct irq_domain *d; + /* - * If no domain has been set through the pcibios_add_device - * callback, inherit the default from the bus device. + * If the platform or firmware interfaces cannot supply a + * device-specific MSI domain, then inherit the default domain + * from the host bridge itself. */ - if (!dev_get_msi_domain(&dev->dev)) - dev_set_msi_domain(&dev->dev, - dev_get_msi_domain(&dev->bus->dev)); + d = pci_dev_msi_domain(dev); + if (!d) + d = dev_get_msi_domain(&dev->bus->dev); + + dev_set_msi_domain(&dev->dev, d); } void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) |