提交 e4802f12 编写于 作者: Y Yicong Yang 提交者: Zhou Juan

hwtracing: hisi_ptt: Fix potential sleep in atomic context

driver inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I7BZYX
CVE: 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: NJonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: NYicong Yang <yangyicong@hisilicon.com>
上级 7648f627
...@@ -341,13 +341,13 @@ static int hisi_ptt_register_irq(struct hisi_ptt *hisi_ptt) ...@@ -341,13 +341,13 @@ static int hisi_ptt_register_irq(struct hisi_ptt *hisi_ptt)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = devm_request_threaded_irq(&pdev->dev, hisi_ptt->trace_irq = pci_irq_vector(pdev, HISI_PTT_TRACE_DMA_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, NULL, hisi_ptt_isr, 0,
DRV_NAME, hisi_ptt); DRV_NAME, hisi_ptt);
if (ret) { if (ret) {
pci_err(pdev, "failed to request irq %d, ret = %d\n", 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; return ret;
} }
...@@ -1098,8 +1098,7 @@ static void hisi_ptt_pmu_start(struct perf_event *event, int flags) ...@@ -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 * core in event_function_local(). If CPU passed is offline we'll fail
* here, just log it since we can do nothing here. * 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), ret = irq_set_affinity(hisi_ptt->trace_irq, cpumask_of(cpu));
cpumask_of(cpu));
if (ret) if (ret)
dev_warn(dev, "failed to set the affinity of trace interrupt\n"); 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) ...@@ -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 * Also make sure the interrupt bind to the migrated CPU as well. Warn
* the user on failure here. * the user on failure here.
*/ */
if (irq_set_affinity(pci_irq_vector(hisi_ptt->pdev, HISI_PTT_TRACE_DMA_IRQ), if (irq_set_affinity(hisi_ptt->trace_irq, cpumask_of(target)))
cpumask_of(target)))
dev_warn(dev, "failed to set the affinity of trace interrupt\n"); dev_warn(dev, "failed to set the affinity of trace interrupt\n");
hisi_ptt->trace_ctrl.on_cpu = target; hisi_ptt->trace_ctrl.on_cpu = target;
......
...@@ -201,6 +201,7 @@ struct hisi_ptt_pmu_buf { ...@@ -201,6 +201,7 @@ struct hisi_ptt_pmu_buf {
* @pdev: pci_dev of this PTT device * @pdev: pci_dev of this PTT device
* @tune_lock: lock to serialize the tune process * @tune_lock: lock to serialize the tune process
* @pmu_lock: lock to serialize the perf 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 * @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 * @lower_bdf: the lower BDF range of the PCI devices managed by this PTT device
* @port_filters: the filter list of root ports * @port_filters: the filter list of root ports
...@@ -221,6 +222,7 @@ struct hisi_ptt { ...@@ -221,6 +222,7 @@ struct hisi_ptt {
struct pci_dev *pdev; struct pci_dev *pdev;
struct mutex tune_lock; struct mutex tune_lock;
spinlock_t pmu_lock; spinlock_t pmu_lock;
int trace_irq;
u32 upper_bdf; u32 upper_bdf;
u32 lower_bdf; u32 lower_bdf;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册