2 * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
3 * Author: Marc Zyngier <marc.zyngier@arm.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include <linux/msi.h>
20 #include <linux/of_irq.h>
21 #include <linux/of_pci.h>
23 #include <linux/irqchip/arm-gic-v3.h>
25 static void its_mask_msi_irq(struct irq_data *d)
28 irq_chip_mask_parent(d);
31 static void its_unmask_msi_irq(struct irq_data *d)
33 pci_msi_unmask_irq(d);
34 irq_chip_unmask_parent(d);
37 static struct irq_chip its_msi_irq_chip = {
39 .irq_unmask = its_unmask_msi_irq,
40 .irq_mask = its_mask_msi_irq,
41 .irq_eoi = irq_chip_eoi_parent,
42 .irq_write_msi_msg = pci_msi_domain_write_msg,
45 struct its_pci_alias {
51 static int its_pci_msi_vec_count(struct pci_dev *pdev)
55 msi = max(pci_msi_vec_count(pdev), 0);
56 msix = max(pci_msix_vec_count(pdev), 0);
58 return max(msi, msix);
61 static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
63 struct its_pci_alias *dev_alias = data;
65 dev_alias->dev_id = alias;
66 if (pdev != dev_alias->pdev)
67 dev_alias->count += its_pci_msi_vec_count(dev_alias->pdev);
72 static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
73 int nvec, msi_alloc_info_t *info)
76 struct its_pci_alias dev_alias;
81 pdev = to_pci_dev(dev);
82 dev_alias.pdev = pdev;
83 dev_alias.count = nvec;
85 pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias);
87 return its_msi_prepare(domain, dev_alias.dev_id, dev_alias.count, info);
90 static struct msi_domain_ops its_pci_msi_ops = {
91 .msi_prepare = its_pci_msi_prepare,
94 static struct msi_domain_info its_pci_msi_domain_info = {
95 .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
96 MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
97 .ops = &its_pci_msi_ops,
98 .chip = &its_msi_irq_chip,
101 struct irq_domain *its_pci_msi_alloc_domain(struct device_node *np,
102 struct irq_domain *parent)
104 return pci_msi_create_irq_domain(np, &its_pci_msi_domain_info, parent);