summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Nowicki <tn@semihalf.com>2016-01-19 08:11:15 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2016-03-08 21:44:01 -0500
commitffa7d6166a9611ed9ad117b56f7f513901b31408 (patch)
tree19157e138c8c52cf13ffb84ebcf647ab06483993
parentdb57d7460ea74de2204ddc303520753f256ea67d (diff)
irqchip/gic-v3: Add ACPI support for GICv3/4 initialization
With the refator of gic_of_init(), GICv3/4 can be initialized by gic_init_bases() with gic distributor base address and gic redistributor region(s). So get the redistributor region base addresses from MADT GIC redistributor subtable, and the distributor base address from GICD subtable to init GICv3 irqchip in ACPI way. Note: GIC redistributor base address may also be provided in GICC structures on systems supporting GICv3 and above if the GIC Redistributors are not in the always-on power domain, this patch didn't implement such feature yet. Acked-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Tomasz Nowicki <tn@semihalf.com> Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--drivers/irqchip/irq-gic-v3.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 31205c7d03e3..2cada42022ee 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -15,10 +15,12 @@
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18#include <linux/acpi.h>
18#include <linux/cpu.h> 19#include <linux/cpu.h>
19#include <linux/cpu_pm.h> 20#include <linux/cpu_pm.h>
20#include <linux/delay.h> 21#include <linux/delay.h>
21#include <linux/interrupt.h> 22#include <linux/interrupt.h>
23#include <linux/irqdomain.h>
22#include <linux/of.h> 24#include <linux/of.h>
23#include <linux/of_address.h> 25#include <linux/of_address.h>
24#include <linux/of_irq.h> 26#include <linux/of_irq.h>
@@ -764,6 +766,15 @@ static int gic_irq_domain_translate(struct irq_domain *d,
764 return 0; 766 return 0;
765 } 767 }
766 768
769 if (is_fwnode_irqchip(fwspec->fwnode)) {
770 if(fwspec->param_count != 2)
771 return -EINVAL;
772
773 *hwirq = fwspec->param[0];
774 *type = fwspec->param[1];
775 return 0;
776 }
777
767 return -EINVAL; 778 return -EINVAL;
768} 779}
769 780
@@ -951,3 +962,129 @@ out_unmap_dist:
951} 962}
952 963
953IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init); 964IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
965
966#ifdef CONFIG_ACPI
967static struct redist_region *redist_regs __initdata;
968static u32 nr_redist_regions __initdata;
969
970static int __init
971gic_acpi_parse_madt_redist(struct acpi_subtable_header *header,
972 const unsigned long end)
973{
974 struct acpi_madt_generic_redistributor *redist =
975 (struct acpi_madt_generic_redistributor *)header;
976 void __iomem *redist_base;
977 static int count = 0;
978
979 redist_base = ioremap(redist->base_address, redist->length);
980 if (!redist_base) {
981 pr_err("Couldn't map GICR region @%llx\n", redist->base_address);
982 return -ENOMEM;
983 }
984
985 redist_regs[count].phys_base = redist->base_address;
986 redist_regs[count].redist_base = redist_base;
987 count++;
988 return 0;
989}
990
991static int __init gic_acpi_match_gicr(struct acpi_subtable_header *header,
992 const unsigned long end)
993{
994 /* Subtable presence means that redist exists, that's it */
995 return 0;
996}
997
998static bool __init acpi_validate_gic_table(struct acpi_subtable_header *header,
999 struct acpi_probe_entry *ape)
1000{
1001 struct acpi_madt_generic_distributor *dist;
1002 int count;
1003
1004 dist = (struct acpi_madt_generic_distributor *)header;
1005 if (dist->version != ape->driver_data)
1006 return false;
1007
1008 /* We need to do that exercise anyway, the sooner the better */
1009 count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
1010 gic_acpi_match_gicr, 0);
1011 if (count <= 0)
1012 return false;
1013
1014 nr_redist_regions = count;
1015 return true;
1016}
1017
1018#define ACPI_GICV3_DIST_MEM_SIZE (SZ_64K)
1019
1020static int __init
1021gic_acpi_init(struct acpi_subtable_header *header, const unsigned long end)
1022{
1023 struct acpi_madt_generic_distributor *dist;
1024 struct fwnode_handle *domain_handle;
1025 void __iomem *dist_base;
1026 int i, err, count;
1027
1028 /* Get distributor base address */
1029 dist = (struct acpi_madt_generic_distributor *)header;
1030 dist_base = ioremap(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE);
1031 if (!dist_base) {
1032 pr_err("Unable to map GICD registers\n");
1033 return -ENOMEM;
1034 }
1035
1036 err = gic_validate_dist_version(dist_base);
1037 if (err) {
1038 pr_err("No distributor detected at @%p, giving up", dist_base);
1039 goto out_dist_unmap;
1040 }
1041
1042 redist_regs = kzalloc(sizeof(*redist_regs) * nr_redist_regions,
1043 GFP_KERNEL);
1044 if (!redist_regs) {
1045 err = -ENOMEM;
1046 goto out_dist_unmap;
1047 }
1048
1049 count = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR,
1050 gic_acpi_parse_madt_redist, 0);
1051 if (count <= 0) {
1052 err = -ENODEV;
1053 goto out_redist_unmap;
1054 }
1055
1056 domain_handle = irq_domain_alloc_fwnode(dist_base);
1057 if (!domain_handle) {
1058 err = -ENOMEM;
1059 goto out_redist_unmap;
1060 }
1061
1062 err = gic_init_bases(dist_base, redist_regs, nr_redist_regions, 0,
1063 domain_handle);
1064 if (err)
1065 goto out_fwhandle_free;
1066
1067 acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
1068 return 0;
1069
1070out_fwhandle_free:
1071 irq_domain_free_fwnode(domain_handle);
1072out_redist_unmap:
1073 for (i = 0; i < nr_redist_regions; i++)
1074 if (redist_regs[i].redist_base)
1075 iounmap(redist_regs[i].redist_base);
1076 kfree(redist_regs);
1077out_dist_unmap:
1078 iounmap(dist_base);
1079 return err;
1080}
1081IRQCHIP_ACPI_DECLARE(gic_v3, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
1082 acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V3,
1083 gic_acpi_init);
1084IRQCHIP_ACPI_DECLARE(gic_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
1085 acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_V4,
1086 gic_acpi_init);
1087IRQCHIP_ACPI_DECLARE(gic_v3_or_v4, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
1088 acpi_validate_gic_table, ACPI_MADT_GIC_VERSION_NONE,
1089 gic_acpi_init);
1090#endif