aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-gic-v3-its.c
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2014-11-24 09:35:17 -0500
committerJason Cooper <jason@lakedaemon.net>2014-11-26 10:55:14 -0500
commit4c21f3c26ecc25c5520628eef8e900a36e6c6ab4 (patch)
tree2760c93d0cceb451be7dde0e093a8f193e3684c9 /drivers/irqchip/irq-gic-v3-its.c
parentb48ac83d6bbc20a973c3e8133fd1ebda873d026a (diff)
irqchip: GICv3: ITS: DT probing and initialization
Add the code that probes the ITS from the device tree, and initialize it. Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Link: https://lkml.kernel.org/r/1416839720-18400-11-git-send-email-marc.zyngier@arm.com Signed-off-by: Jason Cooper <jason@lakedaemon.net>
Diffstat (limited to 'drivers/irqchip/irq-gic-v3-its.c')
-rw-r--r--drivers/irqchip/irq-gic-v3-its.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 532c6df89992..e9d16151eed6 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -1231,3 +1231,172 @@ static const struct irq_domain_ops its_domain_ops = {
1231 .alloc = its_irq_domain_alloc, 1231 .alloc = its_irq_domain_alloc,
1232 .free = its_irq_domain_free, 1232 .free = its_irq_domain_free,
1233}; 1233};
1234
1235static int its_probe(struct device_node *node, struct irq_domain *parent)
1236{
1237 struct resource res;
1238 struct its_node *its;
1239 void __iomem *its_base;
1240 u32 val;
1241 u64 baser, tmp;
1242 int err;
1243
1244 err = of_address_to_resource(node, 0, &res);
1245 if (err) {
1246 pr_warn("%s: no regs?\n", node->full_name);
1247 return -ENXIO;
1248 }
1249
1250 its_base = ioremap(res.start, resource_size(&res));
1251 if (!its_base) {
1252 pr_warn("%s: unable to map registers\n", node->full_name);
1253 return -ENOMEM;
1254 }
1255
1256 val = readl_relaxed(its_base + GITS_PIDR2) & GIC_PIDR2_ARCH_MASK;
1257 if (val != 0x30 && val != 0x40) {
1258 pr_warn("%s: no ITS detected, giving up\n", node->full_name);
1259 err = -ENODEV;
1260 goto out_unmap;
1261 }
1262
1263 pr_info("ITS: %s\n", node->full_name);
1264
1265 its = kzalloc(sizeof(*its), GFP_KERNEL);
1266 if (!its) {
1267 err = -ENOMEM;
1268 goto out_unmap;
1269 }
1270
1271 raw_spin_lock_init(&its->lock);
1272 INIT_LIST_HEAD(&its->entry);
1273 INIT_LIST_HEAD(&its->its_device_list);
1274 its->base = its_base;
1275 its->phys_base = res.start;
1276 its->msi_chip.of_node = node;
1277 its->ite_size = ((readl_relaxed(its_base + GITS_TYPER) >> 4) & 0xf) + 1;
1278
1279 its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL);
1280 if (!its->cmd_base) {
1281 err = -ENOMEM;
1282 goto out_free_its;
1283 }
1284 its->cmd_write = its->cmd_base;
1285
1286 err = its_alloc_tables(its);
1287 if (err)
1288 goto out_free_cmd;
1289
1290 err = its_alloc_collections(its);
1291 if (err)
1292 goto out_free_tables;
1293
1294 baser = (virt_to_phys(its->cmd_base) |
1295 GITS_CBASER_WaWb |
1296 GITS_CBASER_InnerShareable |
1297 (ITS_CMD_QUEUE_SZ / SZ_4K - 1) |
1298 GITS_CBASER_VALID);
1299
1300 writeq_relaxed(baser, its->base + GITS_CBASER);
1301 tmp = readq_relaxed(its->base + GITS_CBASER);
1302 writeq_relaxed(0, its->base + GITS_CWRITER);
1303 writel_relaxed(1, its->base + GITS_CTLR);
1304
1305 if ((tmp ^ baser) & GITS_BASER_SHAREABILITY_MASK) {
1306 pr_info("ITS: using cache flushing for cmd queue\n");
1307 its->flags |= ITS_FLAGS_CMDQ_NEEDS_FLUSHING;
1308 }
1309
1310 if (of_property_read_bool(its->msi_chip.of_node, "msi-controller")) {
1311 its->domain = irq_domain_add_tree(NULL, &its_domain_ops, its);
1312 if (!its->domain) {
1313 err = -ENOMEM;
1314 goto out_free_tables;
1315 }
1316
1317 its->domain->parent = parent;
1318
1319 its->msi_chip.domain = pci_msi_create_irq_domain(node,
1320 &its_pci_msi_domain_info,
1321 its->domain);
1322 if (!its->msi_chip.domain) {
1323 err = -ENOMEM;
1324 goto out_free_domains;
1325 }
1326
1327 err = of_pci_msi_chip_add(&its->msi_chip);
1328 if (err)
1329 goto out_free_domains;
1330 }
1331
1332 spin_lock(&its_lock);
1333 list_add(&its->entry, &its_nodes);
1334 spin_unlock(&its_lock);
1335
1336 return 0;
1337
1338out_free_domains:
1339 if (its->msi_chip.domain)
1340 irq_domain_remove(its->msi_chip.domain);
1341 if (its->domain)
1342 irq_domain_remove(its->domain);
1343out_free_tables:
1344 its_free_tables(its);
1345out_free_cmd:
1346 kfree(its->cmd_base);
1347out_free_its:
1348 kfree(its);
1349out_unmap:
1350 iounmap(its_base);
1351 pr_err("ITS: failed probing %s (%d)\n", node->full_name, err);
1352 return err;
1353}
1354
1355static bool gic_rdists_supports_plpis(void)
1356{
1357 return !!(readl_relaxed(gic_data_rdist_rd_base() + GICR_TYPER) & GICR_TYPER_PLPIS);
1358}
1359
1360int its_cpu_init(void)
1361{
1362 if (!gic_rdists_supports_plpis()) {
1363 pr_info("CPU%d: LPIs not supported\n", smp_processor_id());
1364 return -ENXIO;
1365 }
1366
1367 if (!list_empty(&its_nodes)) {
1368 its_cpu_init_lpis();
1369 its_cpu_init_collection();
1370 }
1371
1372 return 0;
1373}
1374
1375static struct of_device_id its_device_id[] = {
1376 { .compatible = "arm,gic-v3-its", },
1377 {},
1378};
1379
1380int its_init(struct device_node *node, struct rdists *rdists,
1381 struct irq_domain *parent_domain)
1382{
1383 struct device_node *np;
1384
1385 for (np = of_find_matching_node(node, its_device_id); np;
1386 np = of_find_matching_node(np, its_device_id)) {
1387 its_probe(np, parent_domain);
1388 }
1389
1390 if (list_empty(&its_nodes)) {
1391 pr_warn("ITS: No ITS available, not enabling LPIs\n");
1392 return -ENXIO;
1393 }
1394
1395 gic_rdists = rdists;
1396 gic_root_node = node;
1397
1398 its_alloc_lpi_tables();
1399 its_lpi_init(rdists->id_bits);
1400
1401 return 0;
1402}