irqchip/gicv3-its: Split PCI/MSI code from the core ITS driver
[firefly-linux-kernel-4.4.55.git] / drivers / irqchip / irq-gic-v3-its-pci-msi.c
1 /*
2  * Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
3  * Author: Marc Zyngier <marc.zyngier@arm.com>
4  *
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.
8  *
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.
13  *
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/>.
16  */
17
18 #include <linux/msi.h>
19 #include <linux/of.h>
20 #include <linux/of_irq.h>
21 #include <linux/of_pci.h>
22
23 #include <linux/irqchip/arm-gic-v3.h>
24
25 static void its_mask_msi_irq(struct irq_data *d)
26 {
27         pci_msi_mask_irq(d);
28         irq_chip_mask_parent(d);
29 }
30
31 static void its_unmask_msi_irq(struct irq_data *d)
32 {
33         pci_msi_unmask_irq(d);
34         irq_chip_unmask_parent(d);
35 }
36
37 static struct irq_chip its_msi_irq_chip = {
38         .name                   = "ITS-MSI",
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,
43 };
44
45 struct its_pci_alias {
46         struct pci_dev  *pdev;
47         u32             dev_id;
48         u32             count;
49 };
50
51 static int its_pci_msi_vec_count(struct pci_dev *pdev)
52 {
53         int msi, msix;
54
55         msi = max(pci_msi_vec_count(pdev), 0);
56         msix = max(pci_msix_vec_count(pdev), 0);
57
58         return max(msi, msix);
59 }
60
61 static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
62 {
63         struct its_pci_alias *dev_alias = data;
64
65         dev_alias->dev_id = alias;
66         if (pdev != dev_alias->pdev)
67                 dev_alias->count += its_pci_msi_vec_count(dev_alias->pdev);
68
69         return 0;
70 }
71
72 static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
73                                int nvec, msi_alloc_info_t *info)
74 {
75         struct pci_dev *pdev;
76         struct its_pci_alias dev_alias;
77
78         if (!dev_is_pci(dev))
79                 return -EINVAL;
80
81         pdev = to_pci_dev(dev);
82         dev_alias.pdev = pdev;
83         dev_alias.count = nvec;
84
85         pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias);
86
87         return its_msi_prepare(domain, dev_alias.dev_id, dev_alias.count, info);
88 }
89
90 static struct msi_domain_ops its_pci_msi_ops = {
91         .msi_prepare    = its_pci_msi_prepare,
92 };
93
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,
99 };
100
101 struct irq_domain *its_pci_msi_alloc_domain(struct device_node *np,
102                                             struct irq_domain *parent)
103 {
104         return pci_msi_create_irq_domain(np, &its_pci_msi_domain_info, parent);
105 }