Commit 5a848148 authored by Yicong Yang's avatar Yicong Yang Committed by Zhou Juan
Browse files

hwtracing: hisi_ptt: Fix potential sleep in atomic context

driver inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I7BZYX


CVE: NA

Reference: NA

--------------------------------------------------------------------------

From: Yicong Yang <yangyicong@hisilicon.com>

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 82ff8e6b ("PCI/MSI: Use msi_get_virq() in pci_get_vector()")
Fixes: ff0de066 ("hwtracing: hisi_ptt: Add trace function support for HiSilicon PCIe Tune and Trace device")
Reviewed-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: default avatarYicong Yang <yangyicong@hisilicon.com>
parent c6071af9
Loading
Loading
Loading
Loading
+5 −7
Original line number Diff line number Diff line
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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;