summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBharat Bhushan <Bharat.Bhushan@freescale.com>2013-04-17 05:19:06 (GMT)
committerFleming Andrew-AFLEMING <AFLEMING@freescale.com>2013-04-19 23:10:10 (GMT)
commitdb6d844077c0ccfab1a1e6daac1b2dce9e08a3be (patch)
treeaa5a150e18973125458508df0faa6f5e5e2fd19c
parent8b554e04001b8704144c69a5831e8061c393baa6 (diff)
downloadlinux-fsl-qoriq-db6d844077c0ccfab1a1e6daac1b2dce9e08a3be.tar.xz
Add interface to get msi region information
This patch adds interface to get following information - Number of MSI regions (which is number of MSI banks for powerpc). - Get the region address range: Physical page which have the address/addresses used for generating MSI interrupt and size of the page. These are required to create IOMMU (Freescale PAMU) mapping for devices which are directly assigned using VFIO. This patch have hardcoded CCSR_BASE and msi pagesize to 4k. I think this will work as of now but will fix shortly. Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com> Change-Id: Idcd3364cbffb9d8936bd48e67079a4bfa6584b98 Reviewed-on: http://git.am.freescale.net:8181/1489 Reviewed-by: Yoder Stuart-B08248 <stuart.yoder@freescale.com> Reviewed-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com> Tested-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
-rw-r--r--arch/powerpc/include/asm/machdep.h8
-rw-r--r--arch/powerpc/include/asm/pci.h2
-rw-r--r--arch/powerpc/kernel/msi.c18
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c37
-rw-r--r--arch/powerpc/sysdev/fsl_msi.h8
-rw-r--r--drivers/pci/msi.c26
-rw-r--r--include/linux/msi.h9
-rw-r--r--include/linux/pci.h13
8 files changed, 120 insertions, 1 deletions
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 19d9d96..ce449e0 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -29,6 +29,7 @@ struct rtc_time;
struct file;
struct pci_controller;
struct kimage;
+struct msi_region;
struct machdep_calls {
char *name;
@@ -117,6 +118,13 @@ struct machdep_calls {
int (*setup_msi_irqs)(struct pci_dev *dev,
int nvec, int type);
void (*teardown_msi_irqs)(struct pci_dev *dev);
+
+ /* returns the number of MSI regions (banks) */
+ int (*msi_get_region_count)(void);
+
+ /* Returns the request region address and size */
+ int (*msi_get_region)(int region_num,
+ struct msi_region *region);
#endif
void (*restart)(char *cmd);
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 6653f27..e575349 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -117,6 +117,8 @@ extern int pci_proc_domain(struct pci_bus *bus);
#define arch_setup_msi_irqs arch_setup_msi_irqs
#define arch_teardown_msi_irqs arch_teardown_msi_irqs
#define arch_msi_check_device arch_msi_check_device
+#define arch_msi_get_region_count arch_msi_get_region_count
+#define arch_msi_get_region arch_msi_get_region
struct vm_area_struct;
/* Map a range of PCI memory or I/O space for a device into user space */
diff --git a/arch/powerpc/kernel/msi.c b/arch/powerpc/kernel/msi.c
index 8bbc12d..1a67787 100644
--- a/arch/powerpc/kernel/msi.c
+++ b/arch/powerpc/kernel/msi.c
@@ -13,6 +13,24 @@
#include <asm/machdep.h>
+int arch_msi_get_region_count(void)
+{
+ if (ppc_md.msi_get_region_count) {
+ pr_debug("msi: Using platform get_region_count routine.\n");
+ return ppc_md.msi_get_region_count();
+ }
+ return 0;
+}
+
+int arch_msi_get_region(int region_num, struct msi_region *region)
+{
+ if (ppc_md.msi_get_region) {
+ pr_debug("msi: Using platform get_region routine.\n");
+ return ppc_md.msi_get_region(region_num, region);
+ }
+ return 0;
+}
+
int arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
{
if (!ppc_md.setup_msi_irqs || !ppc_md.teardown_msi_irqs) {
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 1b77e55..01f00f2 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -96,6 +96,39 @@ static int fsl_msi_init_allocator(struct fsl_msi *msi_data)
return 0;
}
+static int fsl_msi_get_region_count(void)
+{
+ int count = 0;
+ struct fsl_msi *msi_data;
+
+ list_for_each_entry(msi_data, &msi_head, list)
+ count++;
+
+ return count;
+}
+
+static int fsl_msi_get_region(int region_num, struct msi_region *region)
+{
+ struct fsl_msi *msi_data;
+
+#define CCSR_BASE 0xffe000000
+
+ list_for_each_entry(msi_data, &msi_head, list) {
+ if (msi_data->bank_index == region_num) {
+ region->region_num = msi_data->bank_index;
+ /*
+ * FIXME Get absolute MSIIR address
+ * (remove define CCSR_BASE).
+ */
+ region->addr = CCSR_BASE + msi_data->msiir_offset;
+ region->size = 0x1000;
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
+
static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type)
{
struct fsl_msi *msi;
@@ -405,6 +438,7 @@ static int fsl_of_msi_probe(struct platform_device *dev)
int len;
u32 offset;
static const u32 all_avail[] = { 0, NR_MSI_IRQS };
+ static int bank_index;
match = of_match_device(fsl_of_msi_ids, &dev->dev);
if (!match)
@@ -504,6 +538,7 @@ static int fsl_of_msi_probe(struct platform_device *dev)
}
}
+ msi->bank_index = bank_index++;
list_add_tail(&msi->list, &msi_head);
/* The multiple setting ppc_md.setup_msi_irqs will not harm things */
@@ -511,6 +546,8 @@ static int fsl_of_msi_probe(struct platform_device *dev)
ppc_md.setup_msi_irqs = fsl_setup_msi_irqs;
ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs;
ppc_md.msi_check_device = fsl_msi_check_device;
+ ppc_md.msi_get_region_count = fsl_msi_get_region_count;
+ ppc_md.msi_get_region = fsl_msi_get_region;
} else if (ppc_md.setup_msi_irqs != fsl_setup_msi_irqs) {
dev_err(&dev->dev, "Different MSI driver already installed!\n");
err = -ENODEV;
diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h
index 7389e8e..7a427be 100644
--- a/arch/powerpc/sysdev/fsl_msi.h
+++ b/arch/powerpc/sysdev/fsl_msi.h
@@ -37,6 +37,14 @@ struct fsl_msi {
u32 feature;
int msi_virqs[NR_MSI_REG];
+ /*
+ * During probe each bank is assigned a index number.
+ * index number ranges from 0 to 2^32.
+ * Example MSI bank 1 = 0
+ * MSI bank 2 = 1, and so on.
+ */
+ int bank_index;
+
struct msi_bitmap bitmap;
struct list_head list; /* support multiple MSI banks */
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 5099636..e7da2f3 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -28,6 +28,20 @@ static int pci_msi_enable = 1;
/* Arch hooks */
+#ifndef arch_msi_get_region_count
+int arch_msi_get_region_count(void)
+{
+ return 0;
+}
+#endif
+
+#ifndef arch_msi_get_region
+int arch_msi_get_region(int region_num, struct msi_region *region)
+{
+ return 0;
+}
+#endif
+
#ifndef arch_msi_check_device
int arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
{
@@ -885,6 +899,18 @@ void pci_disable_msi(struct pci_dev *dev)
}
EXPORT_SYMBOL(pci_disable_msi);
+int msi_get_region_count(void)
+{
+ return arch_msi_get_region_count();
+}
+EXPORT_SYMBOL(msi_get_region_count);
+
+int msi_get_region(int region_num, struct msi_region *region)
+{
+ return arch_msi_get_region(region_num, region);
+}
+EXPORT_SYMBOL(msi_get_region);
+
/**
* pci_msix_table_size - return the number of device's MSI-X table entries
* @dev: pointer to the pci_dev data structure of MSI-X device function
diff --git a/include/linux/msi.h b/include/linux/msi.h
index ce93a34..0fcc401 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -49,6 +49,12 @@ struct msi_desc {
struct kobject kobj;
};
+struct msi_region {
+ int region_num;
+ dma_addr_t addr;
+ size_t size;
+};
+
/*
* The arch hook for setup up msi irqs
*/
@@ -57,6 +63,7 @@ void arch_teardown_msi_irq(unsigned int irq);
extern int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type);
extern void arch_teardown_msi_irqs(struct pci_dev *dev);
extern int arch_msi_check_device(struct pci_dev* dev, int nvec, int type);
-
+extern int arch_msi_get_region_count(void);
+extern int arch_msi_get_region(int region_num, struct msi_region *region);
#endif /* LINUX_MSI_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 15472d6..6570843 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1094,6 +1094,7 @@ struct msix_entry {
u16 entry; /* driver uses to specify entry, OS writes */
};
+struct msi_region;
#ifndef CONFIG_PCI_MSI
static inline int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec)
@@ -1130,6 +1131,16 @@ static inline int pci_msi_enabled(void)
{
return 0;
}
+
+static inline int msi_get_region_count(void)
+{
+ return 0;
+}
+
+static inline int msi_get_region(int region_num, struct msi_region *region)
+{
+ return 0;
+}
#else
extern int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec);
extern void pci_msi_shutdown(struct pci_dev *dev);
@@ -1142,6 +1153,8 @@ extern void pci_disable_msix(struct pci_dev *dev);
extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
extern void pci_restore_msi_state(struct pci_dev *dev);
extern int pci_msi_enabled(void);
+extern int msi_get_region_count(void);
+extern int msi_get_region(int region_num, struct msi_region *region);
#endif
#ifdef CONFIG_PCIEPORTBUS