aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorTimur Tabi <timur@freescale.com>2011-10-31 18:06:35 -0400
committerKumar Gala <galak@kernel.crashing.org>2011-11-24 03:01:41 -0500
commit895d603f945baf7d1680b7657561212890e3a803 (patch)
treea403a4c1b186768b276eb2aceefd9b7ec862e3c1 /arch
parentdb9c1870918b08e6cc947c3008fd5aacfc9d6567 (diff)
powerpc/fsl_msi: add support for the fsl, msi property in PCI nodes
On Freescale parts with multiple MSI controllers, the controllers are combined into one "pool" of interrupts. Whenever a device requests an MSI interrupt, the next available interrupt from the pool is selected, regardless of which MSI controller the interrupt is from. This works because each PCI bus has an ATMU to all of CCSR, so any PCI device can access any MSI interrupt register. The fsl,msi property is used to specify that a given PCI bus should only use a specific MSI device. This is necessary, for example, with the Freescale hypervisor, because the MSI devices are assigned to specific partitions. Ideally, we'd like to be able to assign MSI devices to PCI busses within the MSI or PCI layers. However, there does not appear to be a mechanism to do that. Whenever the MSI layer wants to allocate an MSI interrupt to a PCI device, it just calls arch_setup_msi_irqs(). It would be nice if we could register an MSI device with a specific PCI bus. So instead we remember the phandles of each MSI device, and we use that to limit our search for an available interrupt. Whenever we are asked to allocate a new interrupt for a PCI device, we check the fsl,msi property of the PCI bus for that device. If it exists, then as we are looping over all MSI devices, we skip the ones that don't have a matching phandle. Signed-off-by: Timur Tabi <timur@freescale.com> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c39
-rw-r--r--arch/powerpc/sysdev/fsl_msi.h3
2 files changed, 42 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index e5c344d336ea..89548e07ddeb 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -148,14 +148,47 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
148 148
149static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) 149static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
150{ 150{
151 struct pci_controller *hose = pci_bus_to_host(pdev->bus);
152 struct device_node *np;
153 phandle phandle = 0;
151 int rc, hwirq = -ENOMEM; 154 int rc, hwirq = -ENOMEM;
152 unsigned int virq; 155 unsigned int virq;
153 struct msi_desc *entry; 156 struct msi_desc *entry;
154 struct msi_msg msg; 157 struct msi_msg msg;
155 struct fsl_msi *msi_data; 158 struct fsl_msi *msi_data;
156 159
160 /*
161 * If the PCI node has an fsl,msi property, then we need to use it
162 * to find the specific MSI.
163 */
164 np = of_parse_phandle(hose->dn, "fsl,msi", 0);
165 if (np) {
166 if (of_device_is_compatible(np, "fsl,mpic-msi"))
167 phandle = np->phandle;
168 else {
169 dev_err(&pdev->dev, "node %s has an invalid fsl,msi"
170 " phandle\n", hose->dn->full_name);
171 return -EINVAL;
172 }
173 }
174
157 list_for_each_entry(entry, &pdev->msi_list, list) { 175 list_for_each_entry(entry, &pdev->msi_list, list) {
176 /*
177 * Loop over all the MSI devices until we find one that has an
178 * available interrupt.
179 */
158 list_for_each_entry(msi_data, &msi_head, list) { 180 list_for_each_entry(msi_data, &msi_head, list) {
181 /*
182 * If the PCI node has an fsl,msi property, then we
183 * restrict our search to the corresponding MSI node.
184 * The simplest way is to skip over MSI nodes with the
185 * wrong phandle. Under the Freescale hypervisor, this
186 * has the additional benefit of skipping over MSI
187 * nodes that are not mapped in the PAMU.
188 */
189 if (phandle && (phandle != msi_data->phandle))
190 continue;
191
159 hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1); 192 hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
160 if (hwirq >= 0) 193 if (hwirq >= 0)
161 break; 194 break;
@@ -370,6 +403,12 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
370 403
371 msi->msiir_offset = features->msiir_offset + (res.start & 0xfffff); 404 msi->msiir_offset = features->msiir_offset + (res.start & 0xfffff);
372 405
406 /*
407 * Remember the phandle, so that we can match with any PCI nodes
408 * that have an "fsl,msi" property.
409 */
410 msi->phandle = dev->dev.of_node->phandle;
411
373 rc = fsl_msi_init_allocator(msi); 412 rc = fsl_msi_init_allocator(msi);
374 if (rc) { 413 if (rc) {
375 dev_err(&dev->dev, "Error allocating MSI bitmap\n"); 414 dev_err(&dev->dev, "Error allocating MSI bitmap\n");
diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h
index 1313abbc5200..b5d25ba51311 100644
--- a/arch/powerpc/sysdev/fsl_msi.h
+++ b/arch/powerpc/sysdev/fsl_msi.h
@@ -13,6 +13,7 @@
13#ifndef _POWERPC_SYSDEV_FSL_MSI_H 13#ifndef _POWERPC_SYSDEV_FSL_MSI_H
14#define _POWERPC_SYSDEV_FSL_MSI_H 14#define _POWERPC_SYSDEV_FSL_MSI_H
15 15
16#include <linux/of.h>
16#include <asm/msi_bitmap.h> 17#include <asm/msi_bitmap.h>
17 18
18#define NR_MSI_REG 8 19#define NR_MSI_REG 8
@@ -36,6 +37,8 @@ struct fsl_msi {
36 struct msi_bitmap bitmap; 37 struct msi_bitmap bitmap;
37 38
38 struct list_head list; /* support multiple MSI banks */ 39 struct list_head list; /* support multiple MSI banks */
40
41 phandle phandle;
39}; 42};
40 43
41#endif /* _POWERPC_SYSDEV_FSL_MSI_H */ 44#endif /* _POWERPC_SYSDEV_FSL_MSI_H */