// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2021 Western Digital Corporation or its affiliates. * Copyright (C) 2022 Ventana Micro Systems Inc.
*/
/* * Requirements for the downstream irqdomains (or devices): * * 1) Downstream irqdomains (or devices) with atomic MSI update can * happily do imsic_irq_set_affinity() in the process-context on * any CPU so the irqchip of such irqdomains must not set the * IRQCHIP_MOVE_DEFERRED flag. * * 2) Downstream irqdomains (or devices) with non-atomic MSI update * must use imsic_irq_set_affinity() in nterrupt-context upon * the next device interrupt so the irqchip of such irqdomains * must set the IRQCHIP_MOVE_DEFERRED flag.
*/
old_vec = irq_data_get_irq_chip_data(d); if (WARN_ON(!old_vec)) return -ENOENT;
/* If old vector cpu belongs to the target cpumask then do nothing */ if (cpumask_test_cpu(old_vec->cpu, mask_val)) return IRQ_SET_MASK_OK_DONE;
/* If move is already in-flight then return failure */ if (imsic_vector_get_move(old_vec)) return -EBUSY;
/* Get a new vector on the desired set of CPUs */
new_vec = imsic_vector_alloc(old_vec->irq, mask_val); if (!new_vec) return -ENOSPC;
/* * Device having non-atomic MSI update might see an intermediate * state when changing target IMSIC vector from one CPU to another. * * To avoid losing interrupt to such intermediate state, do the * following (just like x86 APIC): * * 1) First write a temporary IMSIC vector to the device which * has MSI address same as the old IMSIC vector but MSI data * matches the new IMSIC vector. * * 2) Next write the new IMSIC vector to the device. * * Based on the above, __imsic_local_sync() must check pending * status of both old MSI data and new MSI data on the old CPU.
*/ if (!irq_can_move_in_process_context(d) &&
new_vec->local_id != old_vec->local_id) { /* Setup temporary vector */
tmp_vec.cpu = old_vec->cpu;
tmp_vec.local_id = new_vec->local_id;
/* Point device to the temporary vector */
imsic_msi_update_msg(irq_get_irq_data(d->irq), &tmp_vec);
}
/* Point device to the new vector */
imsic_msi_update_msg(irq_get_irq_data(d->irq), new_vec);
/* Update irq descriptors with the new vector */
d->chip_data = new_vec;
/* Do nothing if there is no in-flight move */
mvec = imsic_vector_get_move(vec); if (!mvec) return;
/* Do nothing if the old IMSIC vector does not belong to current CPU */ if (mvec->cpu != cpu) return;
/* * The best we can do is force cleanup the old IMSIC vector. * * The challenges over here are same as x86 vector domain so * refer to the comments in irq_force_complete_move() function * implemented at arch/x86/kernel/apic/vector.c.
*/
/* Force cleanup in-flight move */
pr_info("IRQ fixup: irq %d move in progress, old vector cpu %d local_id %d\n",
d->irq, mvec->cpu, mvec->local_id);
imsic_vector_force_move_cleanup(vec);
} #endif
/* * On ACPI based systems, PCI enumeration happens early during boot in * acpi_scan_init(). PCI enumeration expects MSI domain setup before * it calls pci_set_msi_domain(). Hence, unlike in DT where * imsic-platform drive probe happens late during boot, ACPI based * systems need to setup the MSI domain early.
*/ int imsic_platform_acpi_probe(struct fwnode_handle *fwnode)
{ return imsic_platform_probe_common(fwnode);
}
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.