From e6db818a3f51781ba12ac4d52b8773f74d57b06b Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 4 Nov 2020 11:29:41 +0000 Subject: [PATCH 1/2] soundwire: Fix DEBUG_LOCKS_WARN_ON for uninitialized attribute running kernel with CONFIG_DEBUG_LOCKS_ALLOC enabled will below warning: BUG: key ffff502e09807098 has not been registered! DEBUG_LOCKS_WARN_ON(1) WARNING: CPU: 5 PID: 129 at kernel/locking/lockdep.c:4623 lockdep_init_map_waits+0xe8/0x250 Modules linked in: CPU: 5 PID: 129 Comm: kworker/5:1 Tainted: G W 5.10.0-rc1-00277-ged49f224ca3f-dirty #1210 Hardware name: Qualcomm Technologies, Inc. Robotics RB5 (DT) Workqueue: events deferred_probe_work_func pstate: 80c00005 (Nzcv daif +PAN +UAO -TCO BTYPE=--) pc : lockdep_init_map_waits+0xe8/0x250 lr : lockdep_init_map_waits+0xe8/0x250 [ Trimmed ] Call trace: lockdep_init_map_waits+0xe8/0x250 __kernfs_create_file+0x78/0x180 sysfs_add_file_mode_ns+0x94/0x1c8 internal_create_group+0x110/0x3e0 sysfs_create_group+0x18/0x28 devm_device_add_group+0x4c/0xb0 add_all_attributes+0x438/0x490 sdw_slave_sysfs_dpn_init+0x128/0x138 sdw_slave_sysfs_init+0x80/0xa0 sdw_drv_probe+0x94/0x170 really_probe+0x118/0x3e0 driver_probe_device+0x5c/0xc0 [ Trimmed ] CPU: 5 PID: 129 Comm: kworker/5:1 Tainted: G W 5.10.0-rc1-00277-ged49f224ca3f-dirty #1210 Hardware name: Qualcomm Technologies, Inc. Robotics RB5 (DT) Workqueue: events deferred_probe_work_func Call trace: dump_backtrace+0x0/0x1c0 show_stack+0x18/0x68 dump_stack+0xd8/0x134 __warn+0xa0/0x158 report_bug+0xc8/0x178 bug_handler+0x20/0x78 brk_handler+0x70/0xc8 [ Trimmed ] Fix this by initializing dynamically allocated sysfs attribute to keep lockdep happy! Fixes: bcac59029955 ("soundwire: add Slave sysfs support") Signed-off-by: Srinivas Kandagatla Acked-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20201104112941.1134-1-srinivas.kandagatla@linaro.org Signed-off-by: Vinod Koul --- drivers/soundwire/sysfs_slave_dpn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soundwire/sysfs_slave_dpn.c b/drivers/soundwire/sysfs_slave_dpn.c index 05a721ea9830..c4b6543c09fd 100644 --- a/drivers/soundwire/sysfs_slave_dpn.c +++ b/drivers/soundwire/sysfs_slave_dpn.c @@ -37,6 +37,7 @@ static int field##_attribute_alloc(struct device *dev, \ return -ENOMEM; \ dpn_attr->N = N; \ dpn_attr->dir = dir; \ + sysfs_attr_init(&dpn_attr->dev_attr.attr); \ dpn_attr->format_string = format_string; \ dpn_attr->dev_attr.attr.name = __stringify(field); \ dpn_attr->dev_attr.attr.mode = 0444; \ From b7cab9be7c16128a0de21ed7ae67211838813437 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 4 Nov 2020 23:23:58 +0800 Subject: [PATCH 2/2] soundwire: SDCA: detect sdca_cascade interrupt The SoundWire 1.2 specification defines an "SDCA cascade" bit which handles a logical OR of all SDCA interrupt sources (up to 30 defined). Due to limitations of the addressing space, this bit is located in the SDW_DP0_INT register when DP0 is used, or alternatively in the DP0_SDCA_Support_INTSTAT register when DP0 is not used. To allow for both cases to be handled, this bit will be checked in the main device-level interrupt handling code. This will result in the register being read twice if DP0 is enabled, but it's not clear how to optimize this case. It's also more logical to deal with this interrupt at the device than the port level, this bit is really not DP0 specific and its location in the DP0_INTSTAT bit is only due to the lack of free space in SCP_INTSTAT_1. The SDCA_Cascade bit cannot be masked or cleared, so the interrupt handling only forwards the detection to the Slave driver, which will deal with reading the relevant SDCA status bits and clearing them. The bus driver only signals the detection. The communication with the Slave driver is based on the same interrupt callback, with only an extension to provide the status of the sdca_cascade bit. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Reviewed-by: Guennadi Liakhovetski Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20201104152358.9518-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 28 +++++++++++++++++++++++++++- include/linux/soundwire/sdw.h | 4 ++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 8eaf31e76677..ffe4600fd95b 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1424,6 +1424,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) int port_num, stat, ret, count = 0; unsigned long port; bool slave_notify = false; + u8 sdca_cascade = 0; u8 buf, buf2[2], _buf, _buf2[2]; bool parity_check; bool parity_quirk; @@ -1453,6 +1454,16 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) goto io_err; } + if (slave->prop.is_sdca) { + ret = sdw_read(slave, SDW_DP0_INT); + if (ret < 0) { + dev_err(slave->bus->dev, + "SDW_DP0_INT read failed:%d\n", ret); + goto io_err; + } + sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; + } + do { /* * Check parity, bus clash and Slave (impl defined) @@ -1489,6 +1500,10 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) clear |= SDW_SCP_INT1_IMPL_DEF; } + /* the SDCA interrupts are cleared in the codec driver .interrupt_callback() */ + if (sdca_cascade) + slave_notify = true; + /* Check port 0 - 3 interrupts */ port = buf & SDW_SCP_INT1_PORT0_3; @@ -1526,6 +1541,7 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) /* Update the Slave driver */ if (slave_notify && slave->ops && slave->ops->interrupt_callback) { + slave_intr.sdca_cascade = sdca_cascade; slave_intr.control_port = clear; memcpy(slave_intr.port, &port_status, sizeof(slave_intr.port)); @@ -1563,11 +1579,21 @@ static int sdw_handle_slave_alerts(struct sdw_slave *slave) goto io_err; } + if (slave->prop.is_sdca) { + ret = sdw_read(slave, SDW_DP0_INT); + if (ret < 0) { + dev_err(slave->bus->dev, + "SDW_DP0_INT read failed:%d\n", ret); + goto io_err; + } + sdca_cascade = ret & SDW_DP0_SDCA_CASCADE; + } + /* Make sure no interrupts are pending */ buf &= _buf; buf2[0] &= _buf2[0]; buf2[1] &= _buf2[1]; - stat = buf || buf2[0] || buf2[1]; + stat = buf || buf2[0] || buf2[1] || sdca_cascade; /* * Exit loop if Slave is continuously in ALERT state even diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 41cc1192f9aa..f0b01b728640 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -359,6 +359,7 @@ struct sdw_dpn_prop { * @sink_dpn_prop: Sink Data Port N properties * @scp_int1_mask: SCP_INT1_MASK desired settings * @quirks: bitmask identifying deltas from the MIPI specification + * @is_sdca: the Slave supports the SDCA specification */ struct sdw_slave_prop { u32 mipi_revision; @@ -382,6 +383,7 @@ struct sdw_slave_prop { struct sdw_dpn_prop *sink_dpn_prop; u8 scp_int1_mask; u32 quirks; + bool is_sdca; }; #define SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY BIT(0) @@ -479,10 +481,12 @@ struct sdw_slave_id { /** * struct sdw_slave_intr_status - Slave interrupt status + * @sdca_cascade: set if the Slave device reports an SDCA interrupt * @control_port: control port status * @port: data port status */ struct sdw_slave_intr_status { + bool sdca_cascade; u8 control_port; u8 port[15]; };