]> Git Repo - linux.git/blob - drivers/irqchip/irq-gic-v3-its-msi-parent.c
ACPI: CPPC: Adjust debug messages in amd_set_max_freq_ratio() to warn
[linux.git] / drivers / irqchip / irq-gic-v3-its-msi-parent.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (C) 2013-2015 ARM Limited, All Rights Reserved.
3 // Author: Marc Zyngier <[email protected]>
4 // Copyright (C) 2022 Linutronix GmbH
5 // Copyright (C) 2022 Intel
6
7 #include <linux/acpi_iort.h>
8 #include <linux/pci.h>
9
10 #include "irq-gic-common.h"
11 #include "irq-msi-lib.h"
12
13 #define ITS_MSI_FLAGS_REQUIRED  (MSI_FLAG_USE_DEF_DOM_OPS |     \
14                                  MSI_FLAG_USE_DEF_CHIP_OPS |    \
15                                  MSI_FLAG_PCI_MSI_MASK_PARENT)
16
17 #define ITS_MSI_FLAGS_SUPPORTED (MSI_GENERIC_FLAGS_MASK |       \
18                                  MSI_FLAG_PCI_MSIX      |       \
19                                  MSI_FLAG_MULTI_PCI_MSI)
20
21 #ifdef CONFIG_PCI_MSI
22 static int its_pci_msi_vec_count(struct pci_dev *pdev, void *data)
23 {
24         int msi, msix, *count = data;
25
26         msi = max(pci_msi_vec_count(pdev), 0);
27         msix = max(pci_msix_vec_count(pdev), 0);
28         *count += max(msi, msix);
29
30         return 0;
31 }
32
33 static int its_get_pci_alias(struct pci_dev *pdev, u16 alias, void *data)
34 {
35         struct pci_dev **alias_dev = data;
36
37         *alias_dev = pdev;
38
39         return 0;
40 }
41
42 static int its_pci_msi_prepare(struct irq_domain *domain, struct device *dev,
43                                int nvec, msi_alloc_info_t *info)
44 {
45         struct pci_dev *pdev, *alias_dev;
46         struct msi_domain_info *msi_info;
47         int alias_count = 0, minnvec = 1;
48
49         if (!dev_is_pci(dev))
50                 return -EINVAL;
51
52         pdev = to_pci_dev(dev);
53         /*
54          * If pdev is downstream of any aliasing bridges, take an upper
55          * bound of how many other vectors could map to the same DevID.
56          * Also tell the ITS that the signalling will come from a proxy
57          * device, and that special allocation rules apply.
58          */
59         pci_for_each_dma_alias(pdev, its_get_pci_alias, &alias_dev);
60         if (alias_dev != pdev) {
61                 if (alias_dev->subordinate)
62                         pci_walk_bus(alias_dev->subordinate,
63                                      its_pci_msi_vec_count, &alias_count);
64                 info->flags |= MSI_ALLOC_FLAGS_PROXY_DEVICE;
65         }
66
67         /* ITS specific DeviceID, as the core ITS ignores dev. */
68         info->scratchpad[0].ul = pci_msi_domain_get_msi_rid(domain->parent, pdev);
69
70         /*
71          * @domain->msi_domain_info->hwsize contains the size of the
72          * MSI[-X] domain, but vector allocation happens one by one. This
73          * needs some thought when MSI comes into play as the size of MSI
74          * might be unknown at domain creation time and therefore set to
75          * MSI_MAX_INDEX.
76          */
77         msi_info = msi_get_domain_info(domain);
78         if (msi_info->hwsize > nvec)
79                 nvec = msi_info->hwsize;
80
81         /*
82          * Always allocate a power of 2, and special case device 0 for
83          * broken systems where the DevID is not wired (and all devices
84          * appear as DevID 0). For that reason, we generously allocate a
85          * minimum of 32 MSIs for DevID 0. If you want more because all
86          * your devices are aliasing to DevID 0, consider fixing your HW.
87          */
88         nvec = max(nvec, alias_count);
89         if (!info->scratchpad[0].ul)
90                 minnvec = 32;
91         nvec = max_t(int, minnvec, roundup_pow_of_two(nvec));
92
93         msi_info = msi_get_domain_info(domain->parent);
94         return msi_info->ops->msi_prepare(domain->parent, dev, nvec, info);
95 }
96 #else /* CONFIG_PCI_MSI */
97 #define its_pci_msi_prepare     NULL
98 #endif /* !CONFIG_PCI_MSI */
99
100 static int of_pmsi_get_dev_id(struct irq_domain *domain, struct device *dev,
101                                   u32 *dev_id)
102 {
103         int ret, index = 0;
104
105         /* Suck the DeviceID out of the msi-parent property */
106         do {
107                 struct of_phandle_args args;
108
109                 ret = of_parse_phandle_with_args(dev->of_node,
110                                                  "msi-parent", "#msi-cells",
111                                                  index, &args);
112                 if (args.np == irq_domain_get_of_node(domain)) {
113                         if (WARN_ON(args.args_count != 1))
114                                 return -EINVAL;
115                         *dev_id = args.args[0];
116                         break;
117                 }
118                 index++;
119         } while (!ret);
120
121         return ret;
122 }
123
124 int __weak iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
125 {
126         return -1;
127 }
128
129 static int its_pmsi_prepare(struct irq_domain *domain, struct device *dev,
130                             int nvec, msi_alloc_info_t *info)
131 {
132         struct msi_domain_info *msi_info;
133         u32 dev_id;
134         int ret;
135
136         if (dev->of_node)
137                 ret = of_pmsi_get_dev_id(domain->parent, dev, &dev_id);
138         else
139                 ret = iort_pmsi_get_dev_id(dev, &dev_id);
140         if (ret)
141                 return ret;
142
143         /* ITS specific DeviceID, as the core ITS ignores dev. */
144         info->scratchpad[0].ul = dev_id;
145
146         /*
147          * @domain->msi_domain_info->hwsize contains the size of the device
148          * domain, but vector allocation happens one by one.
149          */
150         msi_info = msi_get_domain_info(domain);
151         if (msi_info->hwsize > nvec)
152                 nvec = msi_info->hwsize;
153
154         /* Allocate at least 32 MSIs, and always as a power of 2 */
155         nvec = max_t(int, 32, roundup_pow_of_two(nvec));
156
157         msi_info = msi_get_domain_info(domain->parent);
158         return msi_info->ops->msi_prepare(domain->parent,
159                                           dev, nvec, info);
160 }
161
162 static bool its_init_dev_msi_info(struct device *dev, struct irq_domain *domain,
163                                   struct irq_domain *real_parent, struct msi_domain_info *info)
164 {
165         if (!msi_lib_init_dev_msi_info(dev, domain, real_parent, info))
166                 return false;
167
168         switch(info->bus_token) {
169         case DOMAIN_BUS_PCI_DEVICE_MSI:
170         case DOMAIN_BUS_PCI_DEVICE_MSIX:
171                 /*
172                  * FIXME: This probably should be done after a (not yet
173                  * existing) post domain creation callback once to make
174                  * support for dynamic post-enable MSI-X allocations
175                  * work without having to reevaluate the domain size
176                  * over and over. It is known already at allocation
177                  * time via info->hwsize.
178                  *
179                  * That should work perfectly fine for MSI/MSI-X but needs
180                  * some thoughts for purely software managed MSI domains
181                  * where the index space is only limited artificially via
182                  * %MSI_MAX_INDEX.
183                  */
184                 info->ops->msi_prepare = its_pci_msi_prepare;
185                 break;
186         case DOMAIN_BUS_DEVICE_MSI:
187         case DOMAIN_BUS_WIRED_TO_MSI:
188                 /*
189                  * FIXME: See the above PCI prepare comment. The domain
190                  * size is also known at domain creation time.
191                  */
192                 info->ops->msi_prepare = its_pmsi_prepare;
193                 break;
194         default:
195                 /* Confused. How did the lib return true? */
196                 WARN_ON_ONCE(1);
197                 return false;
198         }
199
200         return true;
201 }
202
203 const struct msi_parent_ops gic_v3_its_msi_parent_ops = {
204         .supported_flags        = ITS_MSI_FLAGS_SUPPORTED,
205         .required_flags         = ITS_MSI_FLAGS_REQUIRED,
206         .bus_select_token       = DOMAIN_BUS_NEXUS,
207         .bus_select_mask        = MATCH_PCI_MSI | MATCH_PLATFORM_MSI,
208         .prefix                 = "ITS-",
209         .init_dev_msi_info      = its_init_dev_msi_info,
210 };
This page took 0.03929 seconds and 4 git commands to generate.