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 static void its_mask_msi_irq(struct irq_data *d)
24 {
25 	pci_msi_mask_irq(d);
26 	irq_chip_mask_parent(d);
27 }
28 
29 static void its_unmask_msi_irq(struct irq_data *d)
30 {
31 	pci_msi_unmask_irq(d);
32 	irq_chip_unmask_parent(d);
33 }
34 
35 static struct irq_chip its_msi_irq_chip = {
36 	.name			= "ITS-MSI",
37 	.irq_unmask		= its_unmask_msi_irq,
38 	.irq_mask		= its_mask_msi_irq,
39 	.irq_eoi		= irq_chip_eoi_parent,
40 	.irq_write_msi_msg	= pci_msi_domain_write_msg,
41 };
42 
43 struct its_pci_alias {
44 	struct pci_dev	*pdev;
45 	u32		dev_id;
46 	u32		count;
47 };
48 
49 static int its_pci_msi_vec_count(struct pci_dev *pdev)
50 {
51 	int msi, msix;
52 
53 	msi = max(pci_msi_vec_count(pdev), 0);
54 	msix = max(pci_msix_vec_count(pdev), 0);
55 
56 	return max(msi, msix);
57 }
58 
59 static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
60 {
61 	struct its_pci_alias *dev_alias = data;
62 
63 	dev_alias->dev_id = alias;
64 	if (pdev != dev_alias->pdev)
65 		dev_alias->count += its_pci_msi_vec_count(pdev);
66 
67 	return 0;
68 }
69 
70 static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
71 			       int nvec, msi_alloc_info_t *info)
72 {
73 	struct pci_dev *pdev;
74 	struct its_pci_alias dev_alias;
75 	struct msi_domain_info *msi_info;
76 
77 	if (!dev_is_pci(dev))
78 		return -EINVAL;
79 
80 	msi_info = msi_get_domain_info(domain->parent);
81 
82 	pdev = to_pci_dev(dev);
83 	dev_alias.pdev = pdev;
84 	dev_alias.count = nvec;
85 
86 	pci_for_each_dma_alias(pdev, its_get_pci_alias, &dev_alias);
87 
88 	/* ITS specific DeviceID, as the core ITS ignores dev. */
89 	info->scratchpad[0].ul = dev_alias.dev_id;
90 
91 	return msi_info->ops->msi_prepare(domain->parent,
92 					  dev, dev_alias.count, info);
93 }
94 
95 static struct msi_domain_ops its_pci_msi_ops = {
96 	.msi_prepare	= its_pci_msi_prepare,
97 };
98 
99 static struct msi_domain_info its_pci_msi_domain_info = {
100 	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
101 		   MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX),
102 	.ops	= &its_pci_msi_ops,
103 	.chip	= &its_msi_irq_chip,
104 };
105 
106 static struct of_device_id its_device_id[] = {
107 	{	.compatible	= "arm,gic-v3-its",	},
108 	{},
109 };
110 
111 static int __init its_pci_msi_init(void)
112 {
113 	struct device_node *np;
114 	struct irq_domain *parent;
115 
116 	for (np = of_find_matching_node(NULL, its_device_id); np;
117 	     np = of_find_matching_node(np, its_device_id)) {
118 		if (!of_property_read_bool(np, "msi-controller"))
119 			continue;
120 
121 		parent = irq_find_matching_host(np, DOMAIN_BUS_NEXUS);
122 		if (!parent || !msi_get_domain_info(parent)) {
123 			pr_err("%s: unable to locate ITS domain\n",
124 			       np->full_name);
125 			continue;
126 		}
127 
128 		if (!pci_msi_create_irq_domain(np, &its_pci_msi_domain_info,
129 					       parent)) {
130 			pr_err("%s: unable to create PCI domain\n",
131 			       np->full_name);
132 			continue;
133 		}
134 
135 		pr_info("PCI/MSI: %s domain created\n", np->full_name);
136 	}
137 
138 	return 0;
139 }
140 early_initcall(its_pci_msi_init);
141