// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2021 Western Digital Corporation or its affiliates. * Copyright (C) 2022 Ventana Micro Systems Inc.
*/
/* * To handle an interrupt, we read the TOPEI CSR and write zero in one * instruction. If TOPEI CSR is non-zero then we translate TOPEI.ID to * Linux interrupt number and let Linux IRQ subsystem handle it.
*/ staticvoid imsic_handle_irq(struct irq_desc *desc)
{ struct irq_chip *chip = irq_desc_get_chip(desc); int cpu = smp_processor_id(); struct imsic_vector *vec; unsignedlong local_id;
/* * Process pending local synchronization instead of waiting * for per-CPU local timer to expire.
*/
imsic_local_sync_all(false);
chained_irq_enter(chip, desc);
while ((local_id = csr_swap(CSR_TOPEI, 0))) {
local_id >>= TOPEI_ID_SHIFT;
if (!imsic_noipi && local_id == IMSIC_IPI_ID) { if (IS_ENABLED(CONFIG_SMP))
ipi_mux_process(); continue;
}
if (unlikely(!imsic->base_domain)) continue;
vec = imsic_vector_from_local_id(cpu, local_id); if (!vec) {
pr_warn_ratelimited("vector not found for local ID 0x%lx\n", local_id); continue;
}
generic_handle_irq(vec->irq);
}
chained_irq_exit(chip, desc);
}
staticint imsic_starting_cpu(unsignedint cpu)
{ /* Mark per-CPU IMSIC state as online */
imsic_state_online();
/* * Interrupts identities might have been enabled/disabled while * this CPU was not running so sync-up local enable/disable state.
*/
imsic_local_sync_all(true);
/* Enable local interrupt delivery */
imsic_local_delivery(true);
/* Setup chained handler to the parent domain interrupt */
irq_set_chained_handler(imsic_parent_irq, imsic_handle_irq);
/* * Setup cpuhp state (must be done after setting imsic_parent_irq) * * Don't disable per-CPU IMSIC file when CPU goes offline * because this affects IPI and the masking/unmasking of * virtual IPIs is done via generic IPI-Mux
*/
cpuhp_setup_state(CPUHP_AP_IRQ_RISCV_IMSIC_STARTING, "irqchip/riscv/imsic:starting",
imsic_starting_cpu, imsic_dying_cpu);
imsic_acpi_fwnode = irq_domain_alloc_named_fwnode("imsic"); if (!imsic_acpi_fwnode) {
pr_err("unable to allocate IMSIC FW node\n"); return -ENOMEM;
}
/* Setup IMSIC state */
rc = imsic_setup_state(imsic_acpi_fwnode, imsic); if (rc) {
pr_err("%pfwP: failed to setup state (error %d)\n", imsic_acpi_fwnode, rc); return rc;
}
/* Do early setup of IMSIC state and IPIs */
rc = imsic_early_probe(imsic_acpi_fwnode); if (rc) {
irq_domain_free_fwnode(imsic_acpi_fwnode);
imsic_acpi_fwnode = NULL; return rc;
}
#ifdef CONFIG_PCI if (!rc)
pci_msi_register_fwnode_provider(&imsic_acpi_get_fwnode); #endif
if (rc)
pr_err("%pfwP: failed to register IMSIC for MSI functionality (error %d)\n",
imsic_acpi_fwnode, rc);
/* * Even if imsic_platform_acpi_probe() fails, the IPI part of IMSIC can * continue to work. So, no need to return failure. This is similar to * DT where IPI works but MSI probe fails for some reason.
*/ return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.