hwtracing: hisi_ptt: Fix potential sleep in atomic context
authorYicong Yang <yangyicong@hisilicon.com>
Wed, 21 Jun 2023 09:28:04 +0000 (17:28 +0800)
committerSuzuki K Poulose <suzuki.poulose@arm.com>
Wed, 21 Jun 2023 10:52:39 +0000 (11:52 +0100)
We're using pci_irq_vector() to obtain the interrupt number and then
bind it to the CPU start perf under the protection of spinlock in
pmu::start(). pci_irq_vector() might sleep since [1] because it will
call msi_domain_get_virq() to get the MSI interrupt number and it
needs to acquire dev->msi.data->mutex. Getting a mutex will sleep on
contention. So use pci_irq_vector() in an atomic context is problematic.

This patch cached the interrupt number in the probe() and uses the
cached data instead to avoid potential sleep.

[1] commit 82ff8e6b78fc ("PCI/MSI: Use msi_get_virq() in pci_get_vector()")

Fixes: ff0de066b463 ("hwtracing: hisi_ptt: Add trace function support for HiSilicon PCIe Tune and Trace device")
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Link: https://lore.kernel.org/r/20230621092804.15120-6-yangyicong@huawei.com
drivers/hwtracing/ptt/hisi_ptt.c
drivers/hwtracing/ptt/hisi_ptt.h

index 103fb6b..ba081b6 100644 (file)
@@ -341,13 +341,13 @@ static int hisi_ptt_register_irq(struct hisi_ptt *hisi_ptt)
        if (ret < 0)
                return ret;
 
-       ret = devm_request_threaded_irq(&pdev->dev,
-                                       pci_irq_vector(pdev, HISI_PTT_TRACE_DMA_IRQ),
+       hisi_ptt->trace_irq = pci_irq_vector(pdev, HISI_PTT_TRACE_DMA_IRQ);
+       ret = devm_request_threaded_irq(&pdev->dev, hisi_ptt->trace_irq,
                                        NULL, hisi_ptt_isr, 0,
                                        DRV_NAME, hisi_ptt);
        if (ret) {
                pci_err(pdev, "failed to request irq %d, ret = %d\n",
-                       pci_irq_vector(pdev, HISI_PTT_TRACE_DMA_IRQ), ret);
+                       hisi_ptt->trace_irq, ret);
                return ret;
        }
 
@@ -1098,8 +1098,7 @@ static void hisi_ptt_pmu_start(struct perf_event *event, int flags)
         * core in event_function_local(). If CPU passed is offline we'll fail
         * here, just log it since we can do nothing here.
         */
-       ret = irq_set_affinity(pci_irq_vector(hisi_ptt->pdev, HISI_PTT_TRACE_DMA_IRQ),
-                                             cpumask_of(cpu));
+       ret = irq_set_affinity(hisi_ptt->trace_irq, cpumask_of(cpu));
        if (ret)
                dev_warn(dev, "failed to set the affinity of trace interrupt\n");
 
@@ -1394,8 +1393,7 @@ static int hisi_ptt_cpu_teardown(unsigned int cpu, struct hlist_node *node)
         * Also make sure the interrupt bind to the migrated CPU as well. Warn
         * the user on failure here.
         */
-       if (irq_set_affinity(pci_irq_vector(hisi_ptt->pdev, HISI_PTT_TRACE_DMA_IRQ),
-                                           cpumask_of(target)))
+       if (irq_set_affinity(hisi_ptt->trace_irq, cpumask_of(target)))
                dev_warn(dev, "failed to set the affinity of trace interrupt\n");
 
        hisi_ptt->trace_ctrl.on_cpu = target;
index 164012d..e17f045 100644 (file)
@@ -201,6 +201,7 @@ struct hisi_ptt_pmu_buf {
  * @pdev:         pci_dev of this PTT device
  * @tune_lock:    lock to serialize the tune process
  * @pmu_lock:     lock to serialize the perf process
+ * @trace_irq:    interrupt number used by trace
  * @upper_bdf:    the upper BDF range of the PCI devices managed by this PTT device
  * @lower_bdf:    the lower BDF range of the PCI devices managed by this PTT device
  * @port_filters: the filter list of root ports
@@ -221,6 +222,7 @@ struct hisi_ptt {
        struct pci_dev *pdev;
        struct mutex tune_lock;
        spinlock_t pmu_lock;
+       int trace_irq;
        u32 upper_bdf;
        u32 lower_bdf;