When we to enable the SMB by perf, the perf sched will call perf_ctx_lock() to close system preempt in event_function_call(). But SMB::enable_smb() use mutex to lock the critical section, which may sleep. BUG: sleeping function called from invalid context at kernel/locking/mutex.c:580 in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 153023, name: perf preempt_count: 2, expected: 0 RCU nest depth: 0, expected: 0 INFO: lockdep is turned off. irq event stamp: 0 hardirqs last enabled at (0): [<0000000000000000>] 0x0 hardirqs last disabled at (0): [<ffffa2983f5c5f40>] copy_process+0xae8/0x2b48 softirqs last enabled at (0): [<ffffa2983f5c5f40>] copy_process+0xae8/0x2b48 softirqs last disabled at (0): [<0000000000000000>] 0x0 CPU: 2 PID: 153023 Comm: perf Kdump: loaded Tainted: G W O 6.5.0-rc4+ #1 Call trace: ... __mutex_lock+0xbc/0xa70 mutex_lock_nested+0x34/0x48 smb_update_buffer+0x58/0x360 [ultrasoc_smb] etm_event_stop+0x204/0x2d8 [coresight] etm_event_del+0x1c/0x30 [coresight] event_sched_out+0x17c/0x3b8 group_sched_out.part.0+0x5c/0x208 __perf_event_disable+0x15c/0x210 event_function+0xe0/0x230 remote_function+0xb4/0xe8 generic_exec_single+0x160/0x268 smp_call_function_single+0x20c/0x2a0 event_function_call+0x20c/0x220 _perf_event_disable+0x5c/0x90 perf_event_for_each_child+0x58/0xc0 _perf_ioctl+0x34c/0x1250 perf_ioctl+0x64/0x98 ... Use spinlock to replace mutex to control driver data access to one at a time. The function copy_to_user() may sleep, it cannot be in a spinlock context, so we can't simply replace it in smb_read(). But we can ensure that only one user gets the SMB device fd by smb_open(), so remove the locks from smb_read() and buffer synchronization is guaranteed by the user. Fixes: 06f5c2926aaa ("drivers/coresight: Add UltraSoc System Memory Buffer driver") Signed-off-by: Junhao He <hejunhao3@huawei.com> Reviewed-by: James Clark <james.clark@arm.com> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Link: https://lore.kernel.org/r/20231114133346.30489-2-hejunhao3@huawei.com
126 lines
4.2 KiB
C
126 lines
4.2 KiB
C
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
|
|
/*
|
|
* Siemens System Memory Buffer driver.
|
|
* Copyright(c) 2022, HiSilicon Limited.
|
|
*/
|
|
|
|
#ifndef _ULTRASOC_SMB_H
|
|
#define _ULTRASOC_SMB_H
|
|
|
|
#include <linux/miscdevice.h>
|
|
#include <linux/spinlock.h>
|
|
|
|
/* Offset of SMB global registers */
|
|
#define SMB_GLB_CFG_REG 0x00
|
|
#define SMB_GLB_EN_REG 0x04
|
|
#define SMB_GLB_INT_REG 0x08
|
|
|
|
/* Offset of SMB logical buffer registers */
|
|
#define SMB_LB_CFG_LO_REG 0x40
|
|
#define SMB_LB_CFG_HI_REG 0x44
|
|
#define SMB_LB_INT_CTRL_REG 0x48
|
|
#define SMB_LB_INT_STS_REG 0x4c
|
|
#define SMB_LB_RD_ADDR_REG 0x5c
|
|
#define SMB_LB_WR_ADDR_REG 0x60
|
|
#define SMB_LB_PURGE_REG 0x64
|
|
|
|
/* Set global config register */
|
|
#define SMB_GLB_CFG_BURST_LEN_MSK GENMASK(11, 4)
|
|
#define SMB_GLB_CFG_IDLE_PRD_MSK GENMASK(15, 12)
|
|
#define SMB_GLB_CFG_MEM_WR_MSK GENMASK(21, 16)
|
|
#define SMB_GLB_CFG_MEM_RD_MSK GENMASK(27, 22)
|
|
#define SMB_GLB_CFG_DEFAULT (FIELD_PREP(SMB_GLB_CFG_BURST_LEN_MSK, 0xf) | \
|
|
FIELD_PREP(SMB_GLB_CFG_IDLE_PRD_MSK, 0xf) | \
|
|
FIELD_PREP(SMB_GLB_CFG_MEM_WR_MSK, 0x3) | \
|
|
FIELD_PREP(SMB_GLB_CFG_MEM_RD_MSK, 0x1b))
|
|
|
|
#define SMB_GLB_EN_HW_ENABLE BIT(0)
|
|
|
|
/* Set global interrupt control register */
|
|
#define SMB_GLB_INT_EN BIT(0)
|
|
#define SMB_GLB_INT_PULSE BIT(1) /* Interrupt type: 1 - Pulse */
|
|
#define SMB_GLB_INT_ACT_H BIT(2) /* Interrupt polarity: 1 - Active high */
|
|
#define SMB_GLB_INT_CFG (SMB_GLB_INT_EN | SMB_GLB_INT_PULSE | \
|
|
SMB_GLB_INT_ACT_H)
|
|
|
|
/* Set logical buffer config register lower 32 bits */
|
|
#define SMB_LB_CFG_LO_EN BIT(0)
|
|
#define SMB_LB_CFG_LO_SINGLE_END BIT(1)
|
|
#define SMB_LB_CFG_LO_INIT BIT(8)
|
|
#define SMB_LB_CFG_LO_CONT BIT(11)
|
|
#define SMB_LB_CFG_LO_FLOW_MSK GENMASK(19, 16)
|
|
#define SMB_LB_CFG_LO_DEFAULT (SMB_LB_CFG_LO_EN | SMB_LB_CFG_LO_SINGLE_END | \
|
|
SMB_LB_CFG_LO_INIT | SMB_LB_CFG_LO_CONT | \
|
|
FIELD_PREP(SMB_LB_CFG_LO_FLOW_MSK, 0xf))
|
|
|
|
/* Set logical buffer config register upper 32 bits */
|
|
#define SMB_LB_CFG_HI_RANGE_UP_MSK GENMASK(15, 8)
|
|
#define SMB_LB_CFG_HI_DEFAULT FIELD_PREP(SMB_LB_CFG_HI_RANGE_UP_MSK, 0xff)
|
|
|
|
/*
|
|
* Set logical buffer interrupt control register.
|
|
* The register control the validity of both real-time events and
|
|
* interrupts. When logical buffer status changes causes to issue
|
|
* an interrupt at the same time as it issues a real-time event.
|
|
* Real-time events are used in SMB driver, which needs to get the buffer
|
|
* status. Interrupts are used in debugger mode.
|
|
* SMB_LB_INT_CTRL_BUF_NOTE_MASK control which events flags or interrupts
|
|
* are valid.
|
|
*/
|
|
#define SMB_LB_INT_CTRL_EN BIT(0)
|
|
#define SMB_LB_INT_CTRL_BUF_NOTE_MSK GENMASK(11, 8)
|
|
#define SMB_LB_INT_CTRL_CFG (SMB_LB_INT_CTRL_EN | \
|
|
FIELD_PREP(SMB_LB_INT_CTRL_BUF_NOTE_MSK, 0xf))
|
|
|
|
/* Set logical buffer interrupt status register */
|
|
#define SMB_LB_INT_STS_NOT_EMPTY_MSK BIT(0)
|
|
#define SMB_LB_INT_STS_BUF_RESET_MSK GENMASK(3, 0)
|
|
#define SMB_LB_INT_STS_RESET FIELD_PREP(SMB_LB_INT_STS_BUF_RESET_MSK, 0xf)
|
|
|
|
#define SMB_LB_PURGE_PURGED BIT(0)
|
|
|
|
#define SMB_REG_ADDR_RES 0
|
|
#define SMB_BUF_ADDR_RES 1
|
|
#define SMB_BUF_ADDR_LO_MSK GENMASK(31, 0)
|
|
|
|
/**
|
|
* struct smb_data_buffer - Details of the buffer used by SMB
|
|
* @buf_base: Memory mapped base address of SMB.
|
|
* @buf_hw_base: SMB buffer start Physical base address, only used 32bits.
|
|
* @buf_size: Size of the buffer.
|
|
* @data_size: Size of the available trace data for SMB.
|
|
* @buf_rdptr: Current read position (index) within the buffer.
|
|
*/
|
|
struct smb_data_buffer {
|
|
void *buf_base;
|
|
u32 buf_hw_base;
|
|
unsigned long buf_size;
|
|
unsigned long data_size;
|
|
unsigned long buf_rdptr;
|
|
};
|
|
|
|
/**
|
|
* struct smb_drv_data - specifics associated to an SMB component
|
|
* @base: Memory mapped base address for SMB component.
|
|
* @csdev: Component vitals needed by the framework.
|
|
* @sdb: Data buffer for SMB.
|
|
* @miscdev: Specifics to handle "/dev/xyz.smb" entry.
|
|
* @spinlock: Control data access to one at a time.
|
|
* @reading: Synchronise user space access to SMB buffer.
|
|
* @pid: Process ID of the process being monitored by the
|
|
* session that is using this component.
|
|
* @mode: How this SMB is being used, perf mode or sysfs mode.
|
|
*/
|
|
struct smb_drv_data {
|
|
void __iomem *base;
|
|
struct coresight_device *csdev;
|
|
struct smb_data_buffer sdb;
|
|
struct miscdevice miscdev;
|
|
spinlock_t spinlock;
|
|
bool reading;
|
|
pid_t pid;
|
|
enum cs_mode mode;
|
|
};
|
|
|
|
#endif
|