• Home
  • Raw
  • Download

Lines Matching +full:gic +full:- +full:v2m +full:- +full:frame

2  * ARM GIC v2m MSI(-X) support
19 #include <linux/dma-iommu.h>
28 #include <linux/irqchip/arm-gic.h>
51 /* APM X-Gene with GICv2m MSI_IIDR register value */
57 /* List of flags for specific v2m implementation */
72 u32 flags; /* v2m flags for specific implementation */
103 struct v2m_data *v2m = irq_data_get_irq_chip_data(data); in gicv2m_compose_msi_msg() local
104 phys_addr_t addr = v2m->res.start + V2M_MSI_SETSPI_NS; in gicv2m_compose_msi_msg()
106 msg->address_hi = upper_32_bits(addr); in gicv2m_compose_msi_msg()
107 msg->address_lo = lower_32_bits(addr); in gicv2m_compose_msi_msg()
108 msg->data = data->hwirq; in gicv2m_compose_msi_msg()
110 if (v2m->flags & GICV2M_NEEDS_SPI_OFFSET) in gicv2m_compose_msi_msg()
111 msg->data -= v2m->spi_offset; in gicv2m_compose_msi_msg()
113 iommu_dma_map_msi_msg(data->irq, msg); in gicv2m_compose_msi_msg()
133 if (is_of_node(domain->parent->fwnode)) { in gicv2m_irq_gic_domain_alloc()
134 fwspec.fwnode = domain->parent->fwnode; in gicv2m_irq_gic_domain_alloc()
137 fwspec.param[1] = hwirq - 32; in gicv2m_irq_gic_domain_alloc()
139 } else if (is_fwnode_irqchip(domain->parent->fwnode)) { in gicv2m_irq_gic_domain_alloc()
140 fwspec.fwnode = domain->parent->fwnode; in gicv2m_irq_gic_domain_alloc()
145 return -EINVAL; in gicv2m_irq_gic_domain_alloc()
153 d = irq_domain_get_irq_data(domain->parent, virq); in gicv2m_irq_gic_domain_alloc()
154 d->chip->irq_set_type(d, IRQ_TYPE_EDGE_RISING); in gicv2m_irq_gic_domain_alloc()
158 static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq, in gicv2m_unalloc_msi() argument
162 bitmap_release_region(v2m->bm, hwirq - v2m->spi_start, in gicv2m_unalloc_msi()
170 struct v2m_data *v2m = NULL, *tmp; in gicv2m_irq_domain_alloc() local
175 offset = bitmap_find_free_region(tmp->bm, tmp->nr_spis, in gicv2m_irq_domain_alloc()
178 v2m = tmp; in gicv2m_irq_domain_alloc()
184 if (!v2m) in gicv2m_irq_domain_alloc()
185 return -ENOSPC; in gicv2m_irq_domain_alloc()
187 hwirq = v2m->spi_start + offset; in gicv2m_irq_domain_alloc()
195 &gicv2m_irq_chip, v2m); in gicv2m_irq_domain_alloc()
202 gicv2m_unalloc_msi(v2m, hwirq, nr_irqs); in gicv2m_irq_domain_alloc()
210 struct v2m_data *v2m = irq_data_get_irq_chip_data(d); in gicv2m_irq_domain_free() local
212 gicv2m_unalloc_msi(v2m, d->hwirq, nr_irqs); in gicv2m_irq_domain_free()
230 num, V2M_MAX_SPI - V2M_MIN_SPI + 1); in is_msi_spi_valid()
252 struct v2m_data *v2m, *tmp; in gicv2m_teardown() local
254 list_for_each_entry_safe(v2m, tmp, &v2m_nodes, entry) { in gicv2m_teardown()
255 list_del(&v2m->entry); in gicv2m_teardown()
256 kfree(v2m->bm); in gicv2m_teardown()
257 iounmap(v2m->base); in gicv2m_teardown()
258 of_node_put(to_of_node(v2m->fwnode)); in gicv2m_teardown()
259 if (is_fwnode_irqchip(v2m->fwnode)) in gicv2m_teardown()
260 irq_domain_free_fwnode(v2m->fwnode); in gicv2m_teardown()
261 kfree(v2m); in gicv2m_teardown()
268 struct v2m_data *v2m; in gicv2m_allocate_domains() local
270 v2m = list_first_entry_or_null(&v2m_nodes, struct v2m_data, entry); in gicv2m_allocate_domains()
271 if (!v2m) in gicv2m_allocate_domains()
274 inner_domain = irq_domain_create_tree(v2m->fwnode, in gicv2m_allocate_domains()
275 &gicv2m_domain_ops, v2m); in gicv2m_allocate_domains()
278 return -ENOMEM; in gicv2m_allocate_domains()
282 inner_domain->parent = parent; in gicv2m_allocate_domains()
283 pci_domain = pci_msi_create_irq_domain(v2m->fwnode, in gicv2m_allocate_domains()
286 plat_domain = platform_msi_create_irq_domain(v2m->fwnode, in gicv2m_allocate_domains()
296 return -ENOMEM; in gicv2m_allocate_domains()
307 struct v2m_data *v2m; in gicv2m_init_one() local
309 v2m = kzalloc(sizeof(struct v2m_data), GFP_KERNEL); in gicv2m_init_one()
310 if (!v2m) { in gicv2m_init_one()
312 return -ENOMEM; in gicv2m_init_one()
315 INIT_LIST_HEAD(&v2m->entry); in gicv2m_init_one()
316 v2m->fwnode = fwnode; in gicv2m_init_one()
318 memcpy(&v2m->res, res, sizeof(struct resource)); in gicv2m_init_one()
320 v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res)); in gicv2m_init_one()
321 if (!v2m->base) { in gicv2m_init_one()
323 ret = -ENOMEM; in gicv2m_init_one()
328 v2m->spi_start = spi_start; in gicv2m_init_one()
329 v2m->nr_spis = nr_spis; in gicv2m_init_one()
331 u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER); in gicv2m_init_one()
333 v2m->spi_start = V2M_MSI_TYPER_BASE_SPI(typer); in gicv2m_init_one()
334 v2m->nr_spis = V2M_MSI_TYPER_NUM_SPI(typer); in gicv2m_init_one()
337 if (!is_msi_spi_valid(v2m->spi_start, v2m->nr_spis)) { in gicv2m_init_one()
338 ret = -EINVAL; in gicv2m_init_one()
343 * APM X-Gene GICv2m implementation has an erratum where in gicv2m_init_one()
351 * is 'spi_number - 32' in gicv2m_init_one()
353 switch (readl_relaxed(v2m->base + V2M_MSI_IIDR)) { in gicv2m_init_one()
355 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; in gicv2m_init_one()
356 v2m->spi_offset = v2m->spi_start; in gicv2m_init_one()
359 v2m->flags |= GICV2M_NEEDS_SPI_OFFSET; in gicv2m_init_one()
360 v2m->spi_offset = 32; in gicv2m_init_one()
364 v2m->bm = kcalloc(BITS_TO_LONGS(v2m->nr_spis), sizeof(long), in gicv2m_init_one()
366 if (!v2m->bm) { in gicv2m_init_one()
367 ret = -ENOMEM; in gicv2m_init_one()
371 list_add_tail(&v2m->entry, &v2m_nodes); in gicv2m_init_one()
374 v2m->spi_start, (v2m->spi_start + v2m->nr_spis - 1)); in gicv2m_init_one()
378 iounmap(v2m->base); in gicv2m_init_one()
380 kfree(v2m); in gicv2m_init_one()
385 { .compatible = "arm,gic-v2m-frame", },
401 if (!of_find_property(child, "msi-controller", NULL)) in gicv2m_of_init()
406 pr_err("Failed to allocate v2m resource.\n"); in gicv2m_of_init()
410 if (!of_property_read_u32(child, "arm,msi-base-spi", in gicv2m_of_init()
412 !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis)) in gicv2m_of_init()
413 pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n", in gicv2m_of_init()
416 ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis, &res); in gicv2m_of_init()
440 /* We only return the fwnode of the first MSI frame. */ in gicv2m_get_fwnode()
445 return data->fwnode; in gicv2m_get_fwnode()
460 return -EINVAL; in acpi_parse_madt_msi()
462 res.start = m->base_address; in acpi_parse_madt_msi()
463 res.end = m->base_address + SZ_4K - 1; in acpi_parse_madt_msi()
466 if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) { in acpi_parse_madt_msi()
467 spi_start = m->spi_base; in acpi_parse_madt_msi()
468 nr_spis = m->spi_count; in acpi_parse_madt_msi()
470 pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n", in acpi_parse_madt_msi()
474 fwnode = irq_domain_alloc_fwnode((void *)m->base_address); in acpi_parse_madt_msi()
477 return -EINVAL; in acpi_parse_madt_msi()
510 return -EINVAL; in gicv2m_acpi_init()
515 return -EINVAL; in gicv2m_acpi_init()