static int mvebu_gicp_probe(struct platform_device *pdev) { struct mvebu_gicp *gicp; struct irq_domain *inner_domain, *plat_domain, *parent_domain; struct device_node *node = pdev->dev.of_node; struct device_node *irq_parent_dn; int ret, i; gicp = devm_kzalloc(&pdev->dev, sizeof(*gicp), GFP_KERNEL); if (!gicp) return -ENOMEM; gicp->dev = &pdev->dev; spin_lock_init(&gicp->spi_lock); gicp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!gicp->res) return -ENODEV; ret = of_property_count_u32_elems(node, "marvell,spi-ranges"); if (ret < 0) return ret; gicp->spi_ranges_cnt = ret / 2; gicp->spi_ranges = devm_kzalloc(&pdev->dev, gicp->spi_ranges_cnt * sizeof(struct mvebu_gicp_spi_range), GFP_KERNEL); if (!gicp->spi_ranges) return -ENOMEM; for (i = 0; i < gicp->spi_ranges_cnt; i++) { of_property_read_u32_index(node, "marvell,spi-ranges", i * 2, &gicp->spi_ranges[i].start); of_property_read_u32_index(node, "marvell,spi-ranges", i * 2 + 1, &gicp->spi_ranges[i].count); gicp->spi_cnt += gicp->spi_ranges[i].count; } gicp->spi_bitmap = devm_kzalloc(&pdev->dev, BITS_TO_LONGS(gicp->spi_cnt) * sizeof(long), GFP_KERNEL); if (!gicp->spi_bitmap) return -ENOMEM; irq_parent_dn = of_irq_find_parent(node); if (!irq_parent_dn) { dev_err(&pdev->dev, "failed to find parent IRQ node\n"); return -ENODEV; } parent_domain = irq_find_host(irq_parent_dn); if (!parent_domain) { dev_err(&pdev->dev, "failed to find parent IRQ domain\n"); return -ENODEV; } inner_domain = irq_domain_create_hierarchy(parent_domain, 0, gicp->spi_cnt, of_node_to_fwnode(node), &gicp_domain_ops, gicp); if (!inner_domain) return -ENOMEM; plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(node), &gicp_msi_domain_info, inner_domain); if (!plat_domain) { irq_domain_remove(inner_domain); return -ENOMEM; } platform_set_drvdata(pdev, gicp); return 0; }
static int __init gicv2m_init_one(struct device_node *node, struct irq_domain *parent) { int ret; struct v2m_data *v2m; struct irq_domain *inner_domain, *pci_domain, *plat_domain; v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL); if (!v2m) { pr_err("Failed to allocate struct v2m_data.\n"); return -ENOMEM; } ret = of_address_to_resource(node, 0, &v2m->res); if (ret) { pr_err("Failed to allocate v2m resource.\n"); goto err_free_v2m; } v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res)); if (!v2m->base) { pr_err("Failed to map GICv2m resource\n"); ret = -ENOMEM; goto err_free_v2m; } if (!of_property_read_u32(node, "arm,msi-base-spi", &v2m->spi_start) && !of_property_read_u32(node, "arm,msi-num-spis", &v2m->nr_spis)) { pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n", v2m->spi_start, v2m->nr_spis); } else { u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER); v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer); v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer); } if (!is_msi_spi_valid(v2m->spi_start, v2m->nr_spis)) { ret = -EINVAL; goto err_iounmap; } v2m->bm = kzalloc(sizeof(long) * BITS_TO_LONGS(v2m->nr_spis), GFP_KERNEL); if (!v2m->bm) { ret = -ENOMEM; goto err_iounmap; } inner_domain = irq_domain_add_tree(node, &gicv2m_domain_ops, v2m); if (!inner_domain) { pr_err("Failed to create GICv2m domain\n"); ret = -ENOMEM; goto err_free_bm; } inner_domain->bus_token = DOMAIN_BUS_NEXUS; inner_domain->parent = parent; pci_domain = pci_msi_create_irq_domain(node, &gicv2m_msi_domain_info, inner_domain); plat_domain = platform_msi_create_irq_domain(node, &gicv2m_pmsi_domain_info, inner_domain); if (!pci_domain || !plat_domain) { pr_err("Failed to create MSI domains\n"); ret = -ENOMEM; goto err_free_domains; } spin_lock_init(&v2m->msi_cnt_lock); pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name, (unsigned long)v2m->res.start, (unsigned long)v2m->res.end, v2m->spi_start, (v2m->spi_start + v2m->nr_spis)); return 0; err_free_domains: if (plat_domain) irq_domain_remove(plat_domain); if (pci_domain) irq_domain_remove(pci_domain); if (inner_domain) irq_domain_remove(inner_domain); err_free_bm: kfree(v2m->bm); err_iounmap: iounmap(v2m->base); err_free_v2m: kfree(v2m); return ret; }