2019-07-25 23:41:54

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 00/40] soundwire: updates for 5.4

The existing upstream code allows for SoundWire devices to be
enumerated and managed by the bus, but streaming is not currently
supported.

Bard Liao, Rander Wang and I did quite a bit of integration/validation
work to close this gap and we now have SoundWire streaming + basic
power managemement on Intel CometLake and IceLake reference
boards. These changes are still preliminary and should not be merged
as is, but it's time to start reviews. While the number of patches is
quite large, each of the changes is quite small.

SOF driver changes will be submitted shortly as well but are still
being validated.

ClockStop modes and synchronized playback on
multiple links are not supported for now and will likely be part of
the next cycle (dependencies on codec drivers and multi-cpu DAI
support).

Acknowledgements: This work would not have been possible without the
support of Slawomir Blauciak and Tomasz Lauda on the SOF side,
currently being reviewed, see
https://github.com/thesofproject/sof/pull/1638

Comments and feedback welcome!

Bard liao (1):
soundwire: include mod_devicetable.h to avoid compiling warnings

Pierre-Louis Bossart (38):
soundwire: add debugfs support
soundwire: cadence_master: add debugfs register dump
soundwire: cadence_master: align debugfs to 8 digits
soundwire: intel: add debugfs register dump
soundwire: intel: move interrupt enable after interrupt handler
registration
soundwire: intel: prevent possible dereference in hw_params
soundwire: intel: fix channel number reported by hardware
soundwire: intel: remove BIOS work-arounds
soundwire: cadence_master: fix usage of CONFIG_UPDATE
soundwire: cadence_master: remove useless wrapper
soundwire: cadence_master: simplify bus clash interrupt clear
soundwire: cadence_master: revisit interrupt settings
soundwire: cadence_master: fix register definition for SLAVE_STATE
soundwire: cadence_master: fix definitions for INTSTAT0/1
soundwire: cadence_master: handle multiple status reports per Slave
soundwire: cadence_master: improve startup sequence with link hw_reset
soundwire: bus: use runtime_pm_get_sync/pm when enabled
soundwire: bus: split handling of Device0 events
soundwire: bus: improve dynamic debug comments for enumeration
soundwire: prototypes for suspend/resume
soundwire: export helpers to find row and column values
soundwire: stream: fix disable sequence
soundwire: cadence_master: use BIOS defaults for frame shape
soundwire: intel: use BIOS information to set clock dividers
soundwire: Add Intel resource management algorithm
soundwire: intel: handle disabled links
soundwire: intel_init: add kernel module parameter to filter out links
soundwire: cadence_master: add kernel parameter to override interrupt
mask
soundwire: intel: move shutdown() callback and don't export symbol
soundwire: intel: add helper for initialization
soundwire: intel: Add basic power management support
soundwire: intel: ignore disabled links for suspend/resume
soundwire: intel: export helper to exit reset
soundwire: intel: disable interrupts on suspend
soundwire: cadence_master: add hw_reset capability in debugfs
soundwire: cadence_master: make clock stop exit configurable on init
soundwire: intel: add pm_runtime support
soundwire: intel: add delay on restart for enumeration

Rander Wang (1):
soundwire: cadence_master: fix divider setting in clock register

drivers/soundwire/Makefile | 4 +-
drivers/soundwire/algo_dynamic_allocation.c | 403 ++++++++++++++++++++
drivers/soundwire/bus.c | 44 ++-
drivers/soundwire/bus.h | 77 +++-
drivers/soundwire/bus_type.c | 3 +
drivers/soundwire/cadence_master.c | 365 ++++++++++++++----
drivers/soundwire/cadence_master.h | 12 +-
drivers/soundwire/debugfs.c | 156 ++++++++
drivers/soundwire/intel.c | 381 +++++++++++++++++-
drivers/soundwire/intel_init.c | 14 +
drivers/soundwire/slave.c | 1 +
drivers/soundwire/stream.c | 53 ++-
include/linux/soundwire/sdw.h | 15 +
13 files changed, 1414 insertions(+), 114 deletions(-)
create mode 100644 drivers/soundwire/algo_dynamic_allocation.c
create mode 100644 drivers/soundwire/debugfs.c

--
2.20.1



2019-07-25 23:42:02

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 01/40] soundwire: add debugfs support

Add base debugfs mechanism for SoundWire bus by creating soundwire
root and master-N and slave-x hierarchy.

Also add SDW Slave SCP, DP0 and DP-N register debug file.

Registers not implemented will print as "XX"

Credits: this patch is based on an earlier internal contribution by
Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. The main change
is the use of scnprintf to avoid known issues with snprintf.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/Makefile | 4 +-
drivers/soundwire/bus.c | 6 ++
drivers/soundwire/bus.h | 24 ++++++
drivers/soundwire/bus_type.c | 3 +
drivers/soundwire/debugfs.c | 156 ++++++++++++++++++++++++++++++++++
drivers/soundwire/slave.c | 1 +
include/linux/soundwire/sdw.h | 4 +
7 files changed, 197 insertions(+), 1 deletion(-)
create mode 100644 drivers/soundwire/debugfs.c

diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile
index fd99a831b92a..88990cac48a7 100644
--- a/drivers/soundwire/Makefile
+++ b/drivers/soundwire/Makefile
@@ -4,7 +4,9 @@
#

#Bus Objs
-soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o
+soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o \
+ debugfs.o
+
obj-$(CONFIG_SOUNDWIRE_BUS) += soundwire-bus.o

#Cadence Objs
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index fe745830a261..5ad4109dc72f 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -49,6 +49,8 @@ int sdw_add_bus_master(struct sdw_bus *bus)
}
}

+ bus->debugfs = sdw_bus_debugfs_init(bus);
+
/*
* Device numbers in SoundWire are 0 through 15. Enumeration device
* number (0), Broadcast device number (15), Group numbers (12 and
@@ -109,6 +111,8 @@ static int sdw_delete_slave(struct device *dev, void *data)
struct sdw_slave *slave = dev_to_sdw_dev(dev);
struct sdw_bus *bus = slave->bus;

+ sdw_slave_debugfs_exit(slave->debugfs);
+
mutex_lock(&bus->bus_lock);

if (slave->dev_num) /* clear dev_num if assigned */
@@ -130,6 +134,8 @@ static int sdw_delete_slave(struct device *dev, void *data)
void sdw_delete_bus_master(struct sdw_bus *bus)
{
device_for_each_child(bus->dev, NULL, sdw_delete_slave);
+
+ sdw_bus_debugfs_exit(bus->debugfs);
}
EXPORT_SYMBOL(sdw_delete_bus_master);

diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
index 3048ca153f22..06ac4adb0074 100644
--- a/drivers/soundwire/bus.h
+++ b/drivers/soundwire/bus.h
@@ -18,6 +18,30 @@ static inline int sdw_acpi_find_slaves(struct sdw_bus *bus)
void sdw_extract_slave_id(struct sdw_bus *bus,
u64 addr, struct sdw_slave_id *id);

+#ifdef CONFIG_DEBUG_FS
+struct dentry *sdw_bus_debugfs_init(struct sdw_bus *bus);
+void sdw_bus_debugfs_exit(struct dentry *d);
+struct dentry *sdw_slave_debugfs_init(struct sdw_slave *slave);
+void sdw_slave_debugfs_exit(struct dentry *d);
+void sdw_debugfs_init(void);
+void sdw_debugfs_exit(void);
+#else
+struct dentry *sdw_bus_debugfs_init(struct sdw_bus *bus)
+{ return NULL; }
+
+void sdw_bus_debugfs_exit(struct dentry *d) {}
+
+struct dentry *sdw_slave_debugfs_init(struct sdw_slave *slave)
+{ return NULL; }
+
+void sdw_slave_debugfs_exit(struct dentry *d) {}
+
+void sdw_debugfs_init(void) {}
+
+void sdw_debugfs_exit(void) {}
+
+#endif
+
enum {
SDW_MSG_FLAG_READ = 0,
SDW_MSG_FLAG_WRITE,
diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c
index 2655602f0cfb..4a465f55039f 100644
--- a/drivers/soundwire/bus_type.c
+++ b/drivers/soundwire/bus_type.c
@@ -6,6 +6,7 @@
#include <linux/pm_domain.h>
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_type.h>
+#include "bus.h"

/**
* sdw_get_device_id - find the matching SoundWire device id
@@ -177,11 +178,13 @@ EXPORT_SYMBOL_GPL(sdw_unregister_driver);

static int __init sdw_bus_init(void)
{
+ sdw_debugfs_init();
return bus_register(&sdw_bus_type);
}

static void __exit sdw_bus_exit(void)
{
+ sdw_debugfs_exit();
bus_unregister(&sdw_bus_type);
}

diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c
new file mode 100644
index 000000000000..8d86e100516e
--- /dev/null
+++ b/drivers/soundwire/debugfs.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// Copyright(c) 2017-19 Intel Corporation.
+
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+#include <linux/soundwire/sdw.h>
+#include <linux/soundwire/sdw_registers.h>
+#include "bus.h"
+
+#ifdef CONFIG_DEBUG_FS
+struct dentry *sdw_debugfs_root;
+#endif
+
+struct dentry *sdw_bus_debugfs_init(struct sdw_bus *bus)
+{
+ struct dentry *d;
+ char name[16];
+
+ if (!sdw_debugfs_root)
+ return NULL;
+
+ /* create the debugfs master-N */
+ snprintf(name, sizeof(name), "master-%d", bus->link_id);
+ d = debugfs_create_dir(name, sdw_debugfs_root);
+
+ return d;
+}
+
+void sdw_bus_debugfs_exit(struct dentry *d)
+{
+ debugfs_remove_recursive(d);
+}
+
+#define RD_BUF (3 * PAGE_SIZE)
+
+static ssize_t sdw_sprintf(struct sdw_slave *slave,
+ char *buf, size_t pos, unsigned int reg)
+{
+ int value;
+
+ value = sdw_read(slave, reg);
+
+ if (value < 0)
+ return scnprintf(buf + pos, RD_BUF - pos, "%3x\tXX\n", reg);
+ else
+ return scnprintf(buf + pos, RD_BUF - pos,
+ "%3x\t%2x\n", reg, value);
+}
+
+static ssize_t sdw_slave_reg_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct sdw_slave *slave = file->private_data;
+ unsigned int reg;
+ char *buf;
+ ssize_t ret;
+ int i, j;
+
+ buf = kzalloc(RD_BUF, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = scnprintf(buf, RD_BUF, "Register Value\n");
+ ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP0\n");
+
+ for (i = 0; i < 6; i++)
+ ret += sdw_sprintf(slave, buf, ret, i);
+
+ ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
+ ret += sdw_sprintf(slave, buf, ret, SDW_DP0_CHANNELEN);
+ for (i = SDW_DP0_SAMPLECTRL1; i <= SDW_DP0_LANECTRL; i++)
+ ret += sdw_sprintf(slave, buf, ret, i);
+
+ ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
+ ret += sdw_sprintf(slave, buf, ret,
+ SDW_DP0_CHANNELEN + SDW_BANK1_OFFSET);
+ for (i = SDW_DP0_SAMPLECTRL1 + SDW_BANK1_OFFSET;
+ i <= SDW_DP0_LANECTRL + SDW_BANK1_OFFSET; i++)
+ ret += sdw_sprintf(slave, buf, ret, i);
+
+ ret += scnprintf(buf + ret, RD_BUF - ret, "\nSCP\n");
+ for (i = SDW_SCP_INT1; i <= SDW_SCP_BANKDELAY; i++)
+ ret += sdw_sprintf(slave, buf, ret, i);
+ for (i = SDW_SCP_DEVID_0; i <= SDW_SCP_DEVID_5; i++)
+ ret += sdw_sprintf(slave, buf, ret, i);
+
+ ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
+ ret += sdw_sprintf(slave, buf, ret, SDW_SCP_FRAMECTRL_B0);
+ ret += sdw_sprintf(slave, buf, ret, SDW_SCP_NEXTFRAME_B0);
+
+ ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
+ ret += sdw_sprintf(slave, buf, ret, SDW_SCP_FRAMECTRL_B1);
+ ret += sdw_sprintf(slave, buf, ret, SDW_SCP_NEXTFRAME_B1);
+
+ for (i = 1; i < 14; i++) {
+ ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP%d\n", i);
+ reg = SDW_DPN_INT(i);
+ for (j = 0; j < 6; j++)
+ ret += sdw_sprintf(slave, buf, ret, reg + j);
+
+ ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
+ reg = SDW_DPN_CHANNELEN_B0(i);
+ for (j = 0; j < 9; j++)
+ ret += sdw_sprintf(slave, buf, ret, reg + j);
+
+ ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
+ reg = SDW_DPN_CHANNELEN_B1(i);
+ for (j = 0; j < 9; j++)
+ ret += sdw_sprintf(slave, buf, ret, reg + j);
+ }
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations sdw_slave_reg_fops = {
+ .open = simple_open,
+ .read = sdw_slave_reg_read,
+ .llseek = default_llseek,
+};
+
+struct dentry *sdw_slave_debugfs_init(struct sdw_slave *slave)
+{
+ struct dentry *master;
+ struct dentry *d;
+ char name[32];
+
+ master = slave->bus->debugfs;
+
+ /* create the debugfs slave-name */
+ snprintf(name, sizeof(name), "%s", dev_name(&slave->dev));
+ d = debugfs_create_dir(name, master);
+
+ debugfs_create_file("registers", 0400, d, slave, &sdw_slave_reg_fops);
+
+ return d;
+}
+
+void sdw_slave_debugfs_exit(struct dentry *d)
+{
+ debugfs_remove_recursive(d);
+}
+
+void sdw_debugfs_init(void)
+{
+ sdw_debugfs_root = debugfs_create_dir("soundwire", NULL);
+}
+
+void sdw_debugfs_exit(void)
+{
+ debugfs_remove_recursive(sdw_debugfs_root);
+}
diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c
index f39a5815e25d..34d8bb995f45 100644
--- a/drivers/soundwire/slave.c
+++ b/drivers/soundwire/slave.c
@@ -56,6 +56,7 @@ static int sdw_slave_add(struct sdw_bus *bus,
mutex_unlock(&bus->bus_lock);
put_device(&slave->dev);
}
+ slave->debugfs = sdw_slave_debugfs_init(slave);

return ret;
}
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index 3b231472464a..a49028e9d666 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -544,6 +544,7 @@ struct sdw_slave_ops {
* @bus: Bus handle
* @ops: Slave callback ops
* @prop: Slave properties
+ * @debugfs: Slave debugfs
* @node: node for bus list
* @port_ready: Port ready completion flag for each Slave port
* @dev_num: Device Number assigned by Bus
@@ -555,6 +556,7 @@ struct sdw_slave {
struct sdw_bus *bus;
const struct sdw_slave_ops *ops;
struct sdw_slave_prop prop;
+ struct dentry *debugfs;
struct list_head node;
struct completion *port_ready;
u16 dev_num;
@@ -731,6 +733,7 @@ struct sdw_master_ops {
* @m_rt_list: List of Master instance of all stream(s) running on Bus. This
* is used to compute and program bus bandwidth, clock, frame shape,
* transport and port parameters
+ * @debugfs: Bus debugfs
* @defer_msg: Defer message
* @clk_stop_timeout: Clock stop timeout computed
* @bank_switch_timeout: Bank switch timeout computed
@@ -750,6 +753,7 @@ struct sdw_bus {
struct sdw_bus_params params;
struct sdw_master_prop prop;
struct list_head m_rt_list;
+ struct dentry *debugfs;
struct sdw_defer defer_msg;
unsigned int clk_stop_timeout;
u32 bank_switch_timeout;
--
2.20.1


2019-07-25 23:42:05

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 03/40] soundwire: cadence_master: align debugfs to 8 digits

SQUASHME

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 91e8bacb83e3..9f611a1fff0a 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -234,7 +234,7 @@ static ssize_t cdns_sprintf(struct sdw_cdns *cdns,
char *buf, size_t pos, unsigned int reg)
{
return scnprintf(buf + pos, RD_BUF - pos,
- "%4x\t%4x\n", reg, cdns_readl(cdns, reg));
+ "%4x\t%8x\n", reg, cdns_readl(cdns, reg));
}

static ssize_t cdns_reg_read(struct file *file, char __user *user_buf,
--
2.20.1


2019-07-25 23:42:08

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 04/40] soundwire: intel: add debugfs register dump

Add debugfs file to dump the Intel SoundWire registers

Credits: this patch is based on an earlier internal contribution by
Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. The main change
is the use of scnprintf to avoid known issues with snprintf.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/intel.c | 115 ++++++++++++++++++++++++++++++++++++++
1 file changed, 115 insertions(+)

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 317873bc0555..aeadc341c0a3 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -6,6 +6,7 @@
*/

#include <linux/acpi.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
@@ -16,6 +17,7 @@
#include <linux/soundwire/sdw.h>
#include <linux/soundwire/sdw_intel.h>
#include "cadence_master.h"
+#include "bus.h"
#include "intel.h"

/* Intel SHIM Registers Definition */
@@ -98,6 +100,7 @@ struct sdw_intel {
struct sdw_cdns cdns;
int instance;
struct sdw_intel_link_res *res;
+ struct dentry *fs;
};

#define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns)
@@ -161,6 +164,115 @@ static int intel_set_bit(void __iomem *base, int offset, u32 value, u32 mask)
return -EAGAIN;
}

+/*
+ * debugfs
+ */
+
+#define RD_BUF (2 * PAGE_SIZE)
+
+static ssize_t intel_sprintf(void __iomem *mem, bool l,
+ char *buf, size_t pos, unsigned int reg)
+{
+ int value;
+
+ if (l)
+ value = intel_readl(mem, reg);
+ else
+ value = intel_readw(mem, reg);
+
+ return scnprintf(buf + pos, RD_BUF - pos, "%4x\t%4x\n", reg, value);
+}
+
+static ssize_t intel_reg_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct sdw_intel *sdw = file->private_data;
+ void __iomem *s = sdw->res->shim;
+ void __iomem *a = sdw->res->alh;
+ char *buf;
+ ssize_t ret;
+ int i, j;
+ unsigned int links, reg;
+
+ buf = kzalloc(RD_BUF, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ links = intel_readl(s, SDW_SHIM_LCAP) & GENMASK(2, 0);
+
+ ret = scnprintf(buf, RD_BUF, "Register Value\n");
+ ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n");
+
+ for (i = 0; i < 4; i++) {
+ reg = SDW_SHIM_LCAP + i * 4;
+ ret += intel_sprintf(s, true, buf, ret, reg);
+ }
+
+ for (i = 0; i < links; i++) {
+ ret += scnprintf(buf + ret, RD_BUF - ret, "\nLink%d\n", i);
+ ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLSCAP(i));
+ ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS0CM(i));
+ ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS1CM(i));
+ ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS2CM(i));
+ ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS3CM(i));
+ ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PCMSCAP(i));
+
+ for (j = 0; j < 8; j++) {
+ ret += intel_sprintf(s, false, buf, ret,
+ SDW_SHIM_PCMSYCHM(i, j));
+ ret += intel_sprintf(s, false, buf, ret,
+ SDW_SHIM_PCMSYCHC(i, j));
+ }
+
+ ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PDMSCAP(i));
+ ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i));
+ ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i));
+ }
+
+ ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKEEN);
+ ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKESTS);
+
+ ret += scnprintf(buf + ret, RD_BUF - ret, "\nALH\n");
+ for (i = 0; i < 8; i++)
+ ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i));
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations intel_reg_fops = {
+ .open = simple_open,
+ .read = intel_reg_read,
+ .llseek = default_llseek,
+};
+
+static void intel_debugfs_init(struct sdw_intel *sdw)
+{
+ struct dentry *root = sdw->cdns.bus.debugfs;
+
+ if (!root)
+ return;
+
+ sdw->fs = debugfs_create_dir("intel-sdw", root);
+ if (IS_ERR_OR_NULL(sdw->fs)) {
+ dev_err(sdw->cdns.dev, "debugfs root creation failed\n");
+ sdw->fs = NULL;
+ return;
+ }
+
+ debugfs_create_file("intel-registers", 0400, sdw->fs, sdw,
+ &intel_reg_fops);
+
+ sdw_cdns_debugfs_init(&sdw->cdns, sdw->fs);
+}
+
+static void intel_debugfs_exit(struct sdw_intel *sdw)
+{
+ debugfs_remove_recursive(sdw->fs);
+}
+
/*
* shim ops
*/
@@ -896,6 +1008,8 @@ static int intel_probe(struct platform_device *pdev)
goto err_dai;
}

+ intel_debugfs_init(sdw);
+
return 0;

err_dai:
@@ -912,6 +1026,7 @@ static int intel_remove(struct platform_device *pdev)

sdw = platform_get_drvdata(pdev);

+ intel_debugfs_exit(sdw);
free_irq(sdw->res->irq, sdw);
snd_soc_unregister_component(sdw->cdns.dev);
sdw_delete_bus_master(&sdw->cdns.bus);
--
2.20.1


2019-07-25 23:42:45

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 15/40] soundwire: cadence_master: handle multiple status reports per Slave

When a Slave reports multiple status in the sticky bits, find the
latest configuration from the mirror of the PING frame status and
update the status directly.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 34 ++++++++++++++++++++++++------
1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 889fa2cd49ae..25d5c7267c15 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -643,13 +643,35 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,

/* first check if Slave reported multiple status */
if (set_status > 1) {
+ u32 val;
+
dev_warn_ratelimited(cdns->dev,
- "Slave reported multiple Status: %d\n",
- mask);
- /*
- * TODO: we need to reread the status here by
- * issuing a PING cmd
- */
+ "Slave %d reported multiple Status: %d\n",
+ i, mask);
+
+ /* re-check latest status extracted from PING commands */
+ val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
+ val >>= (i * 2);
+
+ switch (val & 0x3) {
+ case 0:
+ status[i] = SDW_SLAVE_UNATTACHED;
+ break;
+ case 1:
+ status[i] = SDW_SLAVE_ATTACHED;
+ break;
+ case 2:
+ status[i] = SDW_SLAVE_ALERT;
+ break;
+ default:
+ status[i] = SDW_SLAVE_RESERVED;
+ break;
+ }
+
+ dev_warn_ratelimited(cdns->dev,
+ "Slave %d status updated to %d\n",
+ i, status[i]);
+
}
}

--
2.20.1


2019-07-25 23:42:49

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 18/40] soundwire: bus: split handling of Device0 events

Assigning a device number to a Slave will result in additional events
when it reports its status in a PING frame. There is no point in
dealing with all the other devices in a loop, this can be done when a
non-device0 event happens.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/bus.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 0a45dc5713df..bca378806d00 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -985,6 +985,11 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
ret = sdw_program_device_num(bus);
if (ret)
dev_err(bus->dev, "Slave attach failed: %d\n", ret);
+ /*
+ * programming a device number will have side effects,
+ * so we deal with other devices at a later time
+ */
+ return ret;
}

/* Continue to check other slave statuses */
--
2.20.1


2019-07-25 23:42:53

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 20/40] soundwire: prototypes for suspend/resume

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.h | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
index c0bf6ff00a44..d375bbfead18 100644
--- a/drivers/soundwire/cadence_master.h
+++ b/drivers/soundwire/cadence_master.h
@@ -165,6 +165,9 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);

void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);

+int sdw_cdns_suspend(struct sdw_cdns *cdns);
+bool sdw_cdns_check_resume_status(struct sdw_cdns *cdns);
+
int sdw_cdns_get_stream(struct sdw_cdns *cdns,
struct sdw_cdns_streams *stream,
u32 ch, u32 dir);
--
2.20.1


2019-07-25 23:43:01

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 11/40] soundwire: cadence_master: simplify bus clash interrupt clear

The bus clash interrupts are generated when the status is one, and
also cleared by writing a one. It's overkill/useless to use an OR when
the bit is already set.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 2 --
1 file changed, 2 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index e85e49340986..bdc3ed844829 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -692,7 +692,6 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
if (int_status & CDNS_MCP_INT_CTRL_CLASH) {
/* Slave is driving bit slot during control word */
dev_err_ratelimited(cdns->dev, "Bus clash for control word\n");
- int_status |= CDNS_MCP_INT_CTRL_CLASH;
}

if (int_status & CDNS_MCP_INT_DATA_CLASH) {
@@ -701,7 +700,6 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
* ownership of data bits or Slave gone bonkers
*/
dev_err_ratelimited(cdns->dev, "Bus clash for data word\n");
- int_status |= CDNS_MCP_INT_DATA_CLASH;
}

if (int_status & CDNS_MCP_INT_SLAVE_MASK) {
--
2.20.1


2019-07-25 23:43:02

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 23/40] soundwire: stream: fix disable sequence

When we disable the stream and then call hw_free, two bank switches
will be handled and as a result we re-enable the stream on hw_free.

Make sure the stream is disabled on both banks.

TODO: we need to completely revisit all this and make sure we have a
mirroring mechanism between current and alternate banks.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/stream.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index 53f5e790fcd7..75b9ad1fb1a6 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -1637,7 +1637,24 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
}
}

- return do_bank_switch(stream);
+ ret = do_bank_switch(stream);
+ if (ret < 0) {
+ dev_err(bus->dev, "Bank switch failed: %d\n", ret);
+ return ret;
+ }
+
+ /* make sure alternate bank (previous current) is also disabled */
+ list_for_each_entry(m_rt, &stream->master_list, stream_node) {
+ bus = m_rt->bus;
+ /* Disable port(s) */
+ ret = sdw_enable_disable_ports(m_rt, false);
+ if (ret < 0) {
+ dev_err(bus->dev, "Disable port(s) failed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
}

/**
--
2.20.1


2019-07-25 23:43:07

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 27/40] soundwire: Add Intel resource management algorithm

This algorithm computes bus parameters like clock frequency, frame
shape and port transport parameters based on active stream(s) running
on the bus.

This implementation is optimal for Intel platforms. Developers can
also implement their own .compute_params() callback for specific
resource management algorithm.

Credits: this patch is based on an earlier internal contribution by
Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. All hard-coded
values were removed from the initial contribution to use BIOS
information instead.

FIXME: remove checkpatch report
WARNING: Reusing the krealloc arg is almost always a bug
+ group->rates = krealloc(group->rates,

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/Makefile | 2 +-
drivers/soundwire/algo_dynamic_allocation.c | 403 ++++++++++++++++++++
drivers/soundwire/bus.c | 3 +
drivers/soundwire/bus.h | 46 ++-
drivers/soundwire/stream.c | 20 +
include/linux/soundwire/sdw.h | 5 +
6 files changed, 476 insertions(+), 3 deletions(-)
create mode 100644 drivers/soundwire/algo_dynamic_allocation.c

diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile
index 88990cac48a7..f59a9d4a28fd 100644
--- a/drivers/soundwire/Makefile
+++ b/drivers/soundwire/Makefile
@@ -5,7 +5,7 @@

#Bus Objs
soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o \
- debugfs.o
+ debugfs.o algo_dynamic_allocation.o

obj-$(CONFIG_SOUNDWIRE_BUS) += soundwire-bus.o

diff --git a/drivers/soundwire/algo_dynamic_allocation.c b/drivers/soundwire/algo_dynamic_allocation.c
new file mode 100644
index 000000000000..89edb39162b8
--- /dev/null
+++ b/drivers/soundwire/algo_dynamic_allocation.c
@@ -0,0 +1,403 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// Copyright(c) 2015-18 Intel Corporation.
+
+/*
+ * Bandwidth management algorithm based on 2^n gears
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+#include <linux/soundwire/sdw.h>
+#include "bus.h"
+
+#define SDW_STRM_RATE_GROUPING 1
+
+struct sdw_group_params {
+ unsigned int rate;
+ int full_bw;
+ int payload_bw;
+ int hwidth;
+};
+
+struct sdw_group {
+ unsigned int count;
+ unsigned int max_size;
+ unsigned int *rates;
+};
+
+struct sdw_transport_data {
+ int hstart;
+ int hstop;
+ int block_offset;
+ int sub_block_offset;
+};
+
+static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
+ struct sdw_transport_data *t_data)
+{
+ struct sdw_slave_runtime *s_rt = NULL;
+ struct sdw_port_runtime *p_rt;
+ int port_bo, sample_int;
+ unsigned int rate, bps, ch = 0;
+
+ port_bo = t_data->block_offset;
+
+ list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
+ rate = m_rt->stream->params.rate;
+ bps = m_rt->stream->params.bps;
+ sample_int = (m_rt->bus->params.curr_dr_freq / rate);
+
+ list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
+ ch = sdw_ch_mask_to_ch(p_rt->ch_mask);
+
+ sdw_fill_xport_params(&p_rt->transport_params,
+ p_rt->num, true,
+ SDW_BLK_GRP_CNT_1,
+ sample_int, port_bo, port_bo >> 8,
+ t_data->hstart,
+ t_data->hstop,
+ (SDW_BLK_GRP_CNT_1 * ch), 0x0);
+
+ sdw_fill_port_params(&p_rt->port_params,
+ p_rt->num, bps,
+ SDW_PORT_FLOW_MODE_ISOCH,
+ SDW_PORT_DATA_MODE_NORMAL);
+
+ port_bo += bps * ch;
+ }
+ }
+}
+
+static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
+ struct sdw_group_params *params,
+ int port_bo, int hstop)
+{
+ struct sdw_transport_data t_data = {0};
+ struct sdw_port_runtime *p_rt;
+ struct sdw_bus *bus = m_rt->bus;
+ int sample_int, hstart = 0;
+ unsigned int rate, bps, ch, no_ch;
+
+ rate = m_rt->stream->params.rate;
+ bps = m_rt->stream->params.bps;
+ ch = m_rt->ch_count;
+ sample_int = (bus->params.curr_dr_freq / rate);
+
+ if (rate != params->rate)
+ return;
+
+ t_data.hstop = hstop;
+ hstart = hstop - params->hwidth + 1;
+ t_data.hstart = hstart;
+
+ list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
+ no_ch = sdw_ch_mask_to_ch(p_rt->ch_mask);
+
+ sdw_fill_xport_params(&p_rt->transport_params, p_rt->num,
+ true, SDW_BLK_GRP_CNT_1, sample_int,
+ port_bo, port_bo >> 8, hstart, hstop,
+ (SDW_BLK_GRP_CNT_1 * no_ch), 0x0);
+
+ sdw_fill_port_params(&p_rt->port_params,
+ p_rt->num, bps,
+ SDW_PORT_FLOW_MODE_ISOCH,
+ SDW_PORT_DATA_MODE_NORMAL);
+
+ /* Check for first entry */
+ if (!(p_rt == list_first_entry(&m_rt->port_list,
+ struct sdw_port_runtime,
+ port_node))) {
+ port_bo += bps * ch;
+ continue;
+ }
+
+ t_data.hstart = hstart;
+ t_data.hstop = hstop;
+ t_data.block_offset = port_bo;
+ t_data.sub_block_offset = 0;
+ port_bo += bps * ch;
+ }
+
+ sdw_compute_slave_ports(m_rt, &t_data);
+}
+
+static void _sdw_compute_port_params(struct sdw_bus *bus,
+ struct sdw_group_params *params, int count)
+{
+ struct sdw_master_runtime *m_rt = NULL;
+ int hstop = bus->params.col - 1;
+ int block_offset, port_bo, i;
+
+ /* Run loop for all groups to compute transport parameters */
+ for (i = 0; i < count; i++) {
+ port_bo = 1;
+ block_offset = 1;
+
+ list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
+ sdw_compute_master_ports(m_rt, &params[i],
+ port_bo, hstop);
+
+ block_offset += m_rt->ch_count *
+ m_rt->stream->params.bps;
+ port_bo = block_offset;
+ }
+
+ hstop = hstop - params[i].hwidth;
+ }
+}
+
+static int sdw_compute_group_params(struct sdw_bus *bus,
+ struct sdw_group_params *params,
+ int *rates, int count)
+{
+ struct sdw_master_runtime *m_rt = NULL;
+ int sel_col = bus->params.col;
+ unsigned int rate, bps, ch;
+ int i, column_needed = 0;
+
+ /* Calculate bandwidth per group */
+ for (i = 0; i < count; i++) {
+ params[i].rate = rates[i];
+ params[i].full_bw = bus->params.curr_dr_freq / params[i].rate;
+ }
+
+ list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
+ rate = m_rt->stream->params.rate;
+ bps = m_rt->stream->params.bps;
+ ch = m_rt->ch_count;
+
+ for (i = 0; i < count; i++) {
+ if (rate == params[i].rate)
+ params[i].payload_bw += bps * ch;
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ params[i].hwidth = (sel_col *
+ params[i].payload_bw + params[i].full_bw - 1) /
+ params[i].full_bw;
+
+ column_needed += params[i].hwidth;
+ }
+
+ if (column_needed > sel_col - 1)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sdw_add_element_group_count(struct sdw_group *group,
+ unsigned int rate)
+{
+ int num = group->count;
+ int i;
+
+ for (i = 0; i <= num; i++) {
+ if (rate == group->rates[i])
+ break;
+
+ if (i != num)
+ continue;
+
+ if (group->count >= group->max_size) {
+ group->max_size += 1;
+ group->rates = krealloc(group->rates,
+ (sizeof(int) * group->max_size),
+ GFP_KERNEL);
+ if (!group->rates)
+ return -ENOMEM;
+ }
+
+ group->rates[group->count++] = rate;
+ }
+
+ return 0;
+}
+
+static int sdw_get_group_count(struct sdw_bus *bus,
+ struct sdw_group *group)
+{
+ struct sdw_master_runtime *m_rt;
+ unsigned int rate;
+ int ret = 0;
+
+ group->count = 0;
+ group->max_size = SDW_STRM_RATE_GROUPING;
+ group->rates = kcalloc(group->max_size, sizeof(int), GFP_KERNEL);
+ if (!group->rates)
+ return -ENOMEM;
+
+ list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
+ rate = m_rt->stream->params.rate;
+ if (m_rt == list_first_entry(&bus->m_rt_list,
+ struct sdw_master_runtime,
+ bus_node)) {
+ group->rates[group->count++] = rate;
+
+ } else {
+ ret = sdw_add_element_group_count(group, rate);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * sdw_compute_port_params: Compute transport and port parameters
+ *
+ * @bus: SDW Bus instance
+ */
+static int sdw_compute_port_params(struct sdw_bus *bus)
+{
+ struct sdw_group_params *params = NULL;
+ struct sdw_group group;
+ int ret;
+
+ ret = sdw_get_group_count(bus, &group);
+ if (ret < 0)
+ goto out;
+
+ if (group.count == 0)
+ goto out;
+
+ params = kcalloc(group.count, sizeof(*params), GFP_KERNEL);
+ if (!params) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Compute transport parameters for grouped streams */
+ ret = sdw_compute_group_params(bus, params,
+ &group.rates[0], group.count);
+ if (ret < 0)
+ goto out;
+
+ _sdw_compute_port_params(bus, params, group.count);
+
+out:
+ kfree(params);
+ kfree(group.rates);
+
+ return ret;
+}
+
+static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq)
+{
+ struct sdw_master_prop *prop = &bus->prop;
+ int frame_int, frame_freq;
+ int r, c;
+
+ for (c = 0; c < SDW_FRAME_COLS; c++) {
+ for (r = 0; r < SDW_FRAME_ROWS; r++) {
+ if (sdw_rows[r] != prop->default_row ||
+ sdw_cols[c] != prop->default_col)
+ continue;
+
+ frame_int = sdw_rows[r] * sdw_cols[c];
+ frame_freq = clk_freq / frame_int;
+
+ if ((clk_freq - (frame_freq * SDW_FRAME_CTRL_BITS)) <
+ bus->params.bandwidth)
+ continue;
+
+ bus->params.row = sdw_rows[r];
+ bus->params.col = sdw_cols[c];
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * sdw_compute_bus_params: Compute bus parameters
+ *
+ * @bus: SDW Bus instance
+ */
+static int sdw_compute_bus_params(struct sdw_bus *bus)
+{
+ unsigned int max_dr_freq, curr_dr_freq = 0;
+ struct sdw_master_prop *mstr_prop = NULL;
+ int i, clk_values, ret;
+ bool is_gear = false;
+ u32 *clk_buf;
+
+ mstr_prop = &bus->prop;
+ if (!mstr_prop)
+ return -EINVAL;
+
+ if (mstr_prop->num_clk_gears) {
+ clk_values = mstr_prop->num_clk_gears;
+ clk_buf = mstr_prop->clk_gears;
+ is_gear = true;
+ } else if (mstr_prop->num_clk_freq) {
+ clk_values = mstr_prop->num_clk_freq;
+ clk_buf = mstr_prop->clk_freq;
+ } else {
+ clk_values = 1;
+ clk_buf = NULL;
+ }
+
+ max_dr_freq = mstr_prop->max_clk_freq * SDW_DOUBLE_RATE_FACTOR;
+
+ for (i = 0; i < clk_values; i++) {
+ if (!clk_buf)
+ curr_dr_freq = max_dr_freq;
+ else
+ curr_dr_freq = (is_gear) ?
+ (max_dr_freq >> clk_buf[i]) :
+ clk_buf[i] * SDW_DOUBLE_RATE_FACTOR;
+
+ if (curr_dr_freq <= bus->params.bandwidth)
+ continue;
+
+ break;
+
+ /*
+ * TODO: Check all the Slave(s) port(s) audio modes and find
+ * whether given clock rate is supported with glitchless
+ * transition.
+ */
+ }
+
+ if (i == clk_values)
+ return -EINVAL;
+
+ ret = sdw_select_row_col(bus, curr_dr_freq);
+ if (ret < 0)
+ return -EINVAL;
+
+ bus->params.curr_dr_freq = curr_dr_freq;
+ return 0;
+}
+
+/**
+ * sdw_compute_params: Compute bus, transport and port parameters
+ *
+ * @bus: SDW Bus instance
+ */
+int sdw_compute_params(struct sdw_bus *bus)
+{
+ int ret;
+
+ /* Computes clock frequency, frame shape and frame frequency */
+ ret = sdw_compute_bus_params(bus);
+ if (ret < 0) {
+ dev_err(bus->dev, "Compute bus params failed: %d", ret);
+ return ret;
+ }
+
+ /* Compute transport and port params */
+ ret = sdw_compute_port_params(bus);
+ if (ret < 0) {
+ dev_err(bus->dev, "Compute transport params failed: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(sdw_compute_params);
diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 2354675ef104..76a180578712 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -51,6 +51,9 @@ int sdw_add_bus_master(struct sdw_bus *bus)

bus->debugfs = sdw_bus_debugfs_init(bus);

+ if (!bus->compute_params)
+ bus->compute_params = &sdw_compute_params;
+
/*
* Device numbers in SoundWire are 0 through 15. Enumeration device
* number (0), Broadcast device number (15), Group numbers (12 and
diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
index c57c9c23f6ca..fdb7ce034fdf 100644
--- a/drivers/soundwire/bus.h
+++ b/drivers/soundwire/bus.h
@@ -72,6 +72,7 @@ struct sdw_msg {
};

#define SDW_DOUBLE_RATE_FACTOR 2
+#define SDW_STRM_RATE_GROUPING 1

extern int sdw_rows[SDW_FRAME_ROWS];
extern int sdw_cols[SDW_FRAME_COLS];
@@ -157,9 +158,50 @@ int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg,
int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
u32 addr, size_t count, u16 dev_num, u8 flags, u8 *buf);

+/* Retrieve and return channel count from channel mask */
+static inline int sdw_ch_mask_to_ch(int ch_mask)
+{
+ int c = 0;
+
+ for (c = 0; ch_mask; ch_mask >>= 1)
+ c += ch_mask & 1;
+
+ return c;
+}
+
+/* Fill transport parameter data structure */
+static inline void sdw_fill_xport_params(struct sdw_transport_params *params,
+ int port_num, bool grp_ctrl_valid,
+ int grp_ctrl, int sample_int,
+ int off1, int off2,
+ int hstart, int hstop,
+ int pack_mode, int lane_ctrl)
+{
+ params->port_num = port_num;
+ params->blk_grp_ctrl_valid = grp_ctrl_valid;
+ params->blk_grp_ctrl = grp_ctrl;
+ params->sample_interval = sample_int;
+ params->offset1 = off1;
+ params->offset2 = off2;
+ params->hstart = hstart;
+ params->hstop = hstop;
+ params->blk_pkg_mode = pack_mode;
+ params->lane_ctrl = lane_ctrl;
+}
+
+/* Fill port parameter data structure */
+static inline void sdw_fill_port_params(struct sdw_port_params *params,
+ int port_num, int bps,
+ int flow_mode, int data_mode)
+{
+ params->num = port_num;
+ params->bps = bps;
+ params->flow_mode = flow_mode;
+ params->data_mode = data_mode;
+}
+
/* Read-Modify-Write Slave register */
-static inline int
-sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
+static inline int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
{
int tmp;

diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index 75b9ad1fb1a6..add7c121d084 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -1485,6 +1485,16 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
bus->params.bandwidth += m_rt->stream->params.rate *
m_rt->ch_count * m_rt->stream->params.bps;

+ /* Compute params */
+ if (bus->compute_params) {
+ ret = bus->compute_params(bus);
+ if (ret < 0) {
+ dev_err(bus->dev,
+ "Compute params failed: %d", ret);
+ return ret;
+ }
+ }
+
/* Program params */
ret = sdw_program_params(bus);
if (ret < 0) {
@@ -1704,6 +1714,16 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
bus->params.bandwidth -= m_rt->stream->params.rate *
m_rt->ch_count * m_rt->stream->params.bps;

+ /* Compute params */
+ if (bus->compute_params) {
+ ret = bus->compute_params(bus);
+ if (ret < 0) {
+ dev_err(bus->dev,
+ "Compute params failed: %d", ret);
+ return ret;
+ }
+ }
+
/* Program params */
ret = sdw_program_params(bus);
if (ret < 0) {
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index b6acc436ac80..c7dfc824be80 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -730,6 +730,7 @@ struct sdw_master_ops {
* Bit set implies used number, bit clear implies unused number.
* @bus_lock: bus lock
* @msg_lock: message lock
+ * @compute_params: points to Bus resource management implementation
* @ops: Master callback ops
* @port_ops: Master port callback ops
* @params: Current bus parameters
@@ -752,6 +753,7 @@ struct sdw_bus {
DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
struct mutex bus_lock;
struct mutex msg_lock;
+ int (*compute_params)(struct sdw_bus *bus);
const struct sdw_master_ops *ops;
const struct sdw_master_port_ops *port_ops;
struct sdw_bus_params params;
@@ -852,6 +854,9 @@ struct sdw_stream_runtime {

struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name);
void sdw_release_stream(struct sdw_stream_runtime *stream);
+
+int sdw_compute_params(struct sdw_bus *bus);
+
int sdw_stream_add_master(struct sdw_bus *bus,
struct sdw_stream_config *stream_config,
struct sdw_port_config *port_config,
--
2.20.1


2019-07-25 23:43:08

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 30/40] soundwire: cadence_master: add kernel parameter to override interrupt mask

The code has a set of defaults which may not be relevant in all cases,
add kernel parameter as a helper - mostly for early board bring-up.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 18c6ac026e85..dede55072191 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -20,6 +20,10 @@
#include "bus.h"
#include "cadence_master.h"

+static int interrupt_mask;
+module_param_named(cnds_mcp_int_mask, interrupt_mask, int, 0444);
+MODULE_PARM_DESC(cdns_mcp_int_mask, "Cadence MCP IntMask");
+
#define CDNS_MCP_CONFIG 0x0

#define CDNS_MCP_CONFIG_MCMD_RETRY GENMASK(27, 24)
@@ -830,6 +834,9 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
/* now enable all of the above */
mask |= CDNS_MCP_INT_IRQ;

+ if (interrupt_mask) /* parameter override */
+ mask = interrupt_mask;
+
cdns_writel(cdns, CDNS_MCP_INTMASK, mask);

return do_reset(cdns);
--
2.20.1


2019-07-25 23:43:19

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 36/40] soundwire: intel: disable interrupts on suspend

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 42 +++++++++++++++++-------------
drivers/soundwire/cadence_master.h | 2 +-
drivers/soundwire/intel.c | 6 +++--
3 files changed, 29 insertions(+), 21 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index f486fe15fb46..fa7230b0f200 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -814,33 +814,39 @@ EXPORT_SYMBOL(sdw_cdns_exit_reset);
* sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
* @cdns: Cadence instance
*/
-int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
+int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state)
{
u32 mask;

- cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0,
- CDNS_MCP_SLAVE_INTMASK0_MASK);
- cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1,
- CDNS_MCP_SLAVE_INTMASK1_MASK);
+ if (state) {
+ cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0,
+ CDNS_MCP_SLAVE_INTMASK0_MASK);
+ cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1,
+ CDNS_MCP_SLAVE_INTMASK1_MASK);

- /* enable detection of slave state changes */
- mask = CDNS_MCP_INT_SLAVE_RSVD | CDNS_MCP_INT_SLAVE_ALERT |
- CDNS_MCP_INT_SLAVE_ATTACH | CDNS_MCP_INT_SLAVE_NATTACH;
+ /* enable detection of slave state changes */
+ mask = CDNS_MCP_INT_SLAVE_RSVD | CDNS_MCP_INT_SLAVE_ALERT |
+ CDNS_MCP_INT_SLAVE_ATTACH | CDNS_MCP_INT_SLAVE_NATTACH;

- /* enable detection of bus issues */
- mask |= CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
- CDNS_MCP_INT_PARITY;
+ /* enable detection of bus issues */
+ mask |= CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
+ CDNS_MCP_INT_PARITY;

- /* no detection of port interrupts for now */
+ /* no detection of port interrupts for now */

- /* enable detection of RX fifo level */
- mask |= CDNS_MCP_INT_RX_WL;
+ /* enable detection of RX fifo level */
+ mask |= CDNS_MCP_INT_RX_WL;

- /* now enable all of the above */
- mask |= CDNS_MCP_INT_IRQ;
+ /* now enable all of the above */
+ mask |= CDNS_MCP_INT_IRQ;

- if (interrupt_mask) /* parameter override */
- mask = interrupt_mask;
+ if (interrupt_mask) /* parameter override */
+ mask = interrupt_mask;
+ } else {
+ cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, 0);
+ cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, 0);
+ mask = 0;
+ }

cdns_writel(cdns, CDNS_MCP_INTMASK, mask);

diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
index 2b551f9226f3..1a0ba36dd78f 100644
--- a/drivers/soundwire/cadence_master.h
+++ b/drivers/soundwire/cadence_master.h
@@ -162,7 +162,7 @@ int sdw_cdns_init(struct sdw_cdns *cdns);
int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
struct sdw_cdns_stream_config config);
int sdw_cdns_exit_reset(struct sdw_cdns *cdns);
-int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
+int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state);

void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 9ebe38e4d979..1192d5775484 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -1110,7 +1110,7 @@ static int intel_probe(struct platform_device *pdev)
goto err_init;
}

- ret = sdw_cdns_enable_interrupt(&sdw->cdns);
+ ret = sdw_cdns_enable_interrupt(&sdw->cdns, true);

ret = sdw_cdns_exit_reset(&sdw->cdns);

@@ -1169,6 +1169,8 @@ static int intel_suspend(struct device *dev)
return 0;
}

+ sdw_cdns_enable_interrupt(&sdw->cdns, false);
+
ret = intel_link_power_down(sdw);
if (ret) {
dev_err(dev, "Link power down failed: %d", ret);
@@ -1199,7 +1201,7 @@ static int intel_resume(struct device *dev)
return ret;
}

- sdw_cdns_enable_interrupt(&sdw->cdns);
+ sdw_cdns_enable_interrupt(&sdw->cdns, true);

ret = sdw_cdns_exit_reset(&sdw->cdns);

--
2.20.1


2019-07-25 23:43:29

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 39/40] soundwire: intel: add pm_runtime support

Add basic hooks in DAI .startup and .shutdown callbacks. The SoundWire
IP should be powered between those two calls.

By default the platform_device is in SUSPENDED mode, it is required to
call pm_runtime_set_active() before _enable()

FIXME: do we need to use mark_last_busy()?

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/intel.c | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index db7bf2912767..1394a2322553 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -707,6 +707,23 @@ static void intel_port_cleanup(struct sdw_cdns_dma_data *dma)
}
}

+static int intel_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
+ int ret;
+
+ ret = pm_runtime_get_sync(cdns->dev);
+ if (ret < 0) {
+ dev_err_ratelimited(cdns->dev,
+ "pm_runtime_get_sync failed in %s, ret %d\n",
+ __func__, ret);
+ pm_runtime_put_noidle(cdns->dev);
+ }
+
+ return ret;
+}
+
static int intel_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -829,6 +846,8 @@ void intel_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct sdw_cdns_dma_data *dma;
+ struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
+ int ret;

dma = snd_soc_dai_get_dma_data(dai, substream);
if (!dma)
@@ -836,6 +855,13 @@ void intel_shutdown(struct snd_pcm_substream *substream,

snd_soc_dai_set_dma_data(dai, substream, NULL);
kfree(dma);
+
+ pm_runtime_mark_last_busy(cdns->dev);
+ ret = pm_runtime_put_autosuspend(cdns->dev);
+ if (ret < 0)
+ dev_err_ratelimited(cdns->dev,
+ "pM_runtime_put_autosuspend failed in %s:, ret %d\n",
+ __func__, ret);
}

static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
@@ -851,6 +877,7 @@ static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai,
}

static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
+ .startup = intel_startup,
.hw_params = intel_hw_params,
.hw_free = intel_hw_free,
.shutdown = intel_shutdown,
@@ -1124,6 +1151,15 @@ static int intel_probe(struct platform_device *pdev)

intel_debugfs_init(sdw);

+ /* Enable PM */
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 3000);
+ pm_runtime_use_autosuspend(&pdev->dev);
+
+ pm_runtime_mark_last_busy(&pdev->dev); /* FIXME: needed? */
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
return 0;

err_dai:
@@ -1141,6 +1177,7 @@ static int intel_remove(struct platform_device *pdev)
sdw = platform_get_drvdata(pdev);

if (!sdw->cdns.bus.prop.hw_disabled) {
+ pm_runtime_disable(&pdev->dev);
intel_debugfs_exit(sdw);
free_irq(sdw->res->irq, sdw);
snd_soc_unregister_component(sdw->cdns.dev);
@@ -1212,6 +1249,7 @@ static int intel_resume(struct device *dev)

static const struct dev_pm_ops intel_pm = {
SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume)
+ SET_RUNTIME_PM_OPS(intel_suspend, intel_resume, NULL)
};

static struct platform_driver sdw_intel_drv = {
--
2.20.1


2019-07-25 23:43:35

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 09/40] soundwire: cadence_master: fix usage of CONFIG_UPDATE

Per the hardware documentation, all changes to MCP_CONFIG,
MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL need to be validated with a
self-clearing write to MCP_CONFIG_UPDATE.

For some reason, the existing code only does this write to
CONFIG_UPDATE when enabling interrupts. Add a helper and do the update
when the CONFIG is changed.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 9f611a1fff0a..eb46cf651d62 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -224,6 +224,22 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value)
return -EAGAIN;
}

+/*
+ * all changes to the MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL
+ * need to be confirmed with a write to MCP_CONFIG_UPDATE
+ */
+static int cdns_update_config(struct sdw_cdns *cdns)
+{
+ int ret;
+
+ ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
+ CDNS_MCP_CONFIG_UPDATE_BIT);
+ if (ret < 0)
+ dev_err(cdns->dev, "Config update timedout\n");
+
+ return ret;
+}
+
/*
* debugfs
*/
@@ -758,15 +774,9 @@ static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
*/
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
{
- int ret;
-
_cdns_enable_interrupt(cdns);
- ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
- CDNS_MCP_CONFIG_UPDATE_BIT);
- if (ret < 0)
- dev_err(cdns->dev, "Config update timedout\n");

- return ret;
+ return 0;
}
EXPORT_SYMBOL(sdw_cdns_enable_interrupt);

@@ -943,7 +953,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns)

cdns_writel(cdns, CDNS_MCP_CONFIG, val);

- return 0;
+ /* commit changes */
+ ret = cdns_update_config(cdns);
+
+ return ret;
}
EXPORT_SYMBOL(sdw_cdns_init);

--
2.20.1


2019-07-25 23:43:44

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 33/40] soundwire: intel: Add basic power management support

Implement suspend/resume capabilities (not runtime_pm for now)

Credits: this patch is based on an earlier internal contribution by
Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/intel.c | 102 ++++++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 215dc81cdf73..1477c35f616f 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -12,6 +12,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <sound/pcm_params.h>
+#include <linux/pm_runtime.h>
#include <sound/soc.h>
#include <linux/soundwire/sdw_registers.h>
#include <linux/soundwire/sdw.h>
@@ -278,6 +279,35 @@ static void intel_debugfs_exit(struct sdw_intel *sdw)
/*
* shim ops
*/
+static int intel_link_power_down(struct sdw_intel *sdw)
+{
+ int link_control, spa_mask, cpa_mask, ret;
+ unsigned int link_id = sdw->instance;
+ void __iomem *shim = sdw->res->shim;
+ u16 ioctl;
+
+ /* Glue logic */
+ ioctl = intel_readw(shim, SDW_SHIM_IOCTL(link_id));
+ ioctl |= SDW_SHIM_IOCTL_BKE;
+ ioctl |= SDW_SHIM_IOCTL_COE;
+ intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
+
+ ioctl &= ~(SDW_SHIM_IOCTL_MIF);
+ intel_writew(shim, SDW_SHIM_IOCTL(link_id), ioctl);
+
+ /* Link power down sequence */
+ link_control = intel_readl(shim, SDW_SHIM_LCTL);
+ spa_mask = ~(SDW_SHIM_LCTL_SPA << link_id);
+ cpa_mask = (SDW_SHIM_LCTL_CPA << link_id);
+ link_control &= spa_mask;
+
+ ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask);
+ if (ret < 0)
+ return ret;
+
+ sdw->cdns.link_up = false;
+ return 0;
+}

static int intel_link_power_up(struct sdw_intel *sdw)
{
@@ -300,6 +330,29 @@ static int intel_link_power_up(struct sdw_intel *sdw)
return 0;
}

+static void intel_shim_wake(struct sdw_intel *sdw, bool wake_enable)
+{
+ void __iomem *shim = sdw->res->shim;
+ unsigned int link_id = sdw->instance;
+ u16 wake_en, wake_sts;
+
+ if (wake_enable) {
+ /* Enable the wakeup */
+ intel_writew(shim, SDW_SHIM_WAKEEN,
+ (SDW_SHIM_WAKEEN_ENABLE << link_id));
+ } else {
+ /* Disable the wake up interrupt */
+ wake_en = intel_readw(shim, SDW_SHIM_WAKEEN);
+ wake_en &= ~(SDW_SHIM_WAKEEN_ENABLE << link_id);
+ intel_writew(shim, SDW_SHIM_WAKEEN, wake_en);
+
+ /* Clear wake status */
+ wake_sts = intel_readw(shim, SDW_SHIM_WAKESTS);
+ wake_sts |= (SDW_SHIM_WAKEEN_ENABLE << link_id);
+ intel_writew(shim, SDW_SHIM_WAKESTS_STATUS, wake_sts);
+ }
+}
+
static int intel_shim_init(struct sdw_intel *sdw)
{
void __iomem *shim = sdw->res->shim;
@@ -1095,11 +1148,60 @@ static int intel_remove(struct platform_device *pdev)
return 0;
}

+/*
+ * PM calls
+ */
+
+#ifdef CONFIG_PM
+
+static int intel_suspend(struct device *dev)
+{
+ struct sdw_intel *sdw;
+ int ret;
+
+ sdw = dev_get_drvdata(dev);
+
+ ret = intel_link_power_down(sdw);
+ if (ret) {
+ dev_err(dev, "Link power down failed: %d", ret);
+ return ret;
+ }
+
+ intel_shim_wake(sdw, false);
+
+ return 0;
+}
+
+static int intel_resume(struct device *dev)
+{
+ struct sdw_intel *sdw;
+ int ret;
+
+ sdw = dev_get_drvdata(dev);
+
+ ret = intel_init(sdw);
+ if (ret) {
+ dev_err(dev, "%s failed: %d", __func__, ret);
+ return ret;
+ }
+
+ sdw_cdns_enable_interrupt(&sdw->cdns);
+
+ return ret;
+}
+
+#endif
+
+static const struct dev_pm_ops intel_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume)
+};
+
static struct platform_driver sdw_intel_drv = {
.probe = intel_probe,
.remove = intel_remove,
.driver = {
.name = "int-sdw",
+ .pm = &intel_pm,

},
};
--
2.20.1


2019-07-25 23:43:50

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 34/40] soundwire: intel: ignore disabled links for suspend/resume

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/intel.c | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 1477c35f616f..a976480d6f36 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -1161,6 +1161,12 @@ static int intel_suspend(struct device *dev)

sdw = dev_get_drvdata(dev);

+ if (sdw->cdns.bus.prop.hw_disabled) {
+ dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
+ sdw->cdns.bus.link_id);
+ return 0;
+ }
+
ret = intel_link_power_down(sdw);
if (ret) {
dev_err(dev, "Link power down failed: %d", ret);
@@ -1179,6 +1185,12 @@ static int intel_resume(struct device *dev)

sdw = dev_get_drvdata(dev);

+ if (sdw->cdns.bus.prop.hw_disabled) {
+ dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
+ sdw->cdns.bus.link_id);
+ return 0;
+ }
+
ret = intel_init(sdw);
if (ret) {
dev_err(dev, "%s failed: %d", __func__, ret);
--
2.20.1


2019-07-25 23:43:54

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 29/40] soundwire: intel_init: add kernel module parameter to filter out links

The hardware and ACPI info may report the presence of links that are
not physically enabled (e.g. due to pin-muxing or hardware reworks),
which in turn can result in errors being thrown. This shouldn't be the
case for production devices but will happen a lot on development
devices - even more so when they expose a connector.

Add a module parameter to filter out such links, e.g. adding the
following config to a file in /etc/modprobe.d will select the second
and third links only.

options soundwire_intel_init sdw_link_mask=0x6

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/intel_init.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/drivers/soundwire/intel_init.c b/drivers/soundwire/intel_init.c
index 70637a0383d2..6ae8bb13f907 100644
--- a/drivers/soundwire/intel_init.c
+++ b/drivers/soundwire/intel_init.c
@@ -22,6 +22,10 @@
#define SDW_LINK_BASE 0x30000
#define SDW_LINK_SIZE 0x10000

+static int link_mask;
+module_param_named(sdw_link_mask, link_mask, int, 0444);
+MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)");
+
struct sdw_link_data {
struct sdw_intel_link_res res;
struct platform_device *pdev;
@@ -83,6 +87,9 @@ static struct sdw_intel_ctx
caps = ioread32(res->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
caps &= GENMASK(2, 0);

+ dev_dbg(&adev->dev, "SoundWire links: BIOS count %d hardware caps %d\n",
+ count, caps);
+
/* Check HW supported vs property value and use min of two */
count = min_t(u8, caps, count);

@@ -111,6 +118,13 @@ static struct sdw_intel_ctx

/* Create SDW Master devices */
for (i = 0; i < count; i++) {
+ if (link_mask && !(link_mask & BIT(i))) {
+ dev_dbg(&adev->dev,
+ "Link %d masked, will not be enabled\n", i);
+ link++;
+ continue;
+ }
+
link->res.irq = res->irq;
link->res.registers = res->mmio_base + SDW_LINK_BASE
+ (SDW_LINK_SIZE * i);
--
2.20.1


2019-07-25 23:43:59

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 32/40] soundwire: intel: add helper for initialization

Move code to helper for reuse in power management routines

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/intel.c | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index c40ab443e723..215dc81cdf73 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -984,6 +984,15 @@ static struct sdw_master_ops sdw_intel_ops = {
.post_bank_switch = intel_post_bank_switch,
};

+static int intel_init(struct sdw_intel *sdw)
+{
+ /* Initialize shim and controller */
+ intel_link_power_up(sdw);
+ intel_shim_init(sdw);
+
+ return sdw_cdns_init(&sdw->cdns);
+}
+
/*
* probe and init
*/
@@ -1026,11 +1035,8 @@ static int intel_probe(struct platform_device *pdev)
return 0;
}

- /* Initialize shim and controller */
- intel_link_power_up(sdw);
- intel_shim_init(sdw);
-
- ret = sdw_cdns_init(&sdw->cdns);
+ /* Initialize shim, controller and Cadence IP */
+ ret = intel_init(sdw);
if (ret)
goto err_init;

--
2.20.1


2019-07-25 23:44:00

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 31/40] soundwire: intel: move shutdown() callback and don't export symbol

All DAI callbacks are in intel.c except for shutdown. Move and remove
export symbol

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 14 --------------
drivers/soundwire/cadence_master.h | 2 --
drivers/soundwire/intel.c | 17 +++++++++++++++--
3 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index dede55072191..4a189e487830 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -1381,19 +1381,5 @@ int sdw_cdns_alloc_stream(struct sdw_cdns *cdns,
}
EXPORT_SYMBOL(sdw_cdns_alloc_stream);

-void sdw_cdns_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct sdw_cdns_dma_data *dma;
-
- dma = snd_soc_dai_get_dma_data(dai, substream);
- if (!dma)
- return;
-
- snd_soc_dai_set_dma_data(dai, substream, NULL);
- kfree(dma);
-}
-EXPORT_SYMBOL(sdw_cdns_shutdown);
-
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("Cadence Soundwire Library");
diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
index d375bbfead18..de97bc22acb7 100644
--- a/drivers/soundwire/cadence_master.h
+++ b/drivers/soundwire/cadence_master.h
@@ -177,8 +177,6 @@ int sdw_cdns_alloc_stream(struct sdw_cdns *cdns,
void sdw_cdns_config_stream(struct sdw_cdns *cdns, struct sdw_cdns_port *port,
u32 ch, u32 dir, struct sdw_cdns_pdi *pdi);

-void sdw_cdns_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai);
int sdw_cdns_pcm_set_stream(struct snd_soc_dai *dai,
void *stream, int direction);
int sdw_cdns_pdm_set_stream(struct snd_soc_dai *dai,
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 5947fa8e840b..c40ab443e723 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -772,6 +772,19 @@ intel_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
return ret;
}

+void intel_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct sdw_cdns_dma_data *dma;
+
+ dma = snd_soc_dai_get_dma_data(dai, substream);
+ if (!dma)
+ return;
+
+ snd_soc_dai_set_dma_data(dai, substream, NULL);
+ kfree(dma);
+}
+
static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
void *stream, int direction)
{
@@ -787,14 +800,14 @@ static int intel_pdm_set_sdw_stream(struct snd_soc_dai *dai,
static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
.hw_params = intel_hw_params,
.hw_free = intel_hw_free,
- .shutdown = sdw_cdns_shutdown,
+ .shutdown = intel_shutdown,
.set_sdw_stream = intel_pcm_set_sdw_stream,
};

static const struct snd_soc_dai_ops intel_pdm_dai_ops = {
.hw_params = intel_hw_params,
.hw_free = intel_hw_free,
- .shutdown = sdw_cdns_shutdown,
+ .shutdown = intel_shutdown,
.set_sdw_stream = intel_pdm_set_sdw_stream,
};

--
2.20.1


2019-07-25 23:44:06

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 37/40] soundwire: cadence_master: add hw_reset capability in debugfs

This is to kick devices into reset and see what software does

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index fa7230b0f200..53278aa2436f 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -331,6 +331,25 @@ static const struct file_operations cdns_reg_fops = {
.llseek = default_llseek,
};

+static int cdns_hw_reset(void *data, u64 value)
+{
+ struct sdw_cdns *cdns = data;
+ int ret;
+
+ if (value != 1)
+ return 0;
+
+ dev_info(cdns->dev, "starting link hw_reset\n");
+
+ ret = sdw_cdns_exit_reset(cdns);
+
+ dev_info(cdns->dev, "link hw_reset done\n");
+
+ return ret;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(cdns_hw_reset_fops, NULL, cdns_hw_reset, "%llu\n");
+
/**
* sdw_cdns_debugfs_init() - Cadence debugfs init
* @cdns: Cadence instance
@@ -339,6 +358,9 @@ static const struct file_operations cdns_reg_fops = {
void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root)
{
debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);
+
+ debugfs_create_file_unsafe("cdns-hw-reset", 0200, root, cdns,
+ &cdns_hw_reset_fops);
}
EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init);

--
2.20.1


2019-07-25 23:44:09

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 26/40] soundwire: cadence_master: fix divider setting in clock register

From: Rander Wang <[email protected]>

The existing code uses an OR operation which would mix the original
divider setting with the new one, resulting in an invalid
configuration that can make codecs hang.

Add the mask definition and use cdns_updatel to update divider

Signed-off-by: Rander Wang <[email protected]>
Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 10ebcef2e84e..18c6ac026e85 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -57,6 +57,7 @@
#define CDNS_MCP_SSP_CTRL1 0x28
#define CDNS_MCP_CLK_CTRL0 0x30
#define CDNS_MCP_CLK_CTRL1 0x38
+#define CDNS_MCP_CLK_MCLKD_MASK GENMASK(7, 0)

#define CDNS_MCP_STAT 0x40

@@ -988,9 +989,11 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
/* Set clock divider */
divider = (prop->mclk_freq / prop->max_clk_freq) - 1;
val = cdns_readl(cdns, CDNS_MCP_CLK_CTRL0);
- val |= divider;
- cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
- cdns_writel(cdns, CDNS_MCP_CLK_CTRL1, val);
+
+ cdns_updatel(cdns, CDNS_MCP_CLK_CTRL0,
+ CDNS_MCP_CLK_MCLKD_MASK, divider);
+ cdns_updatel(cdns, CDNS_MCP_CLK_CTRL1,
+ CDNS_MCP_CLK_MCLKD_MASK, divider);

pr_err("plb: mclk %d max_freq %d divider %d register %x\n",
prop->mclk_freq,
@@ -1064,8 +1067,7 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
mcp_clkctrl_off = CDNS_MCP_CLK_CTRL0;

mcp_clkctrl = cdns_readl(cdns, mcp_clkctrl_off);
- mcp_clkctrl |= divider;
- cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl);
+ cdns_updatel(cdns, mcp_clkctrl_off, CDNS_MCP_CLK_MCLKD_MASK, divider);

pr_err("plb: mclk * 2 %d curr_dr_freq %d divider %d register %x\n",
prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR,
--
2.20.1


2019-07-25 23:44:13

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 28/40] soundwire: intel: handle disabled links

On most hardware platforms, SoundWire interfaces are pin-muxed with
other interfaces (typically DMIC or I2S) and the status of each link
needs to be checked at boot time.

For Intel platforms, the BIOS provides a menu to enable/disable the
links separately, and the information is provided to the OS with an
Intel-specific _DSD property. The same capability will be added to
revisions of the MIPI DisCo specification.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/intel.c | 26 ++++++++++++++++++++++----
include/linux/soundwire/sdw.h | 2 ++
2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 796ac2bc8cea..5947fa8e840b 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -90,6 +90,8 @@
#define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0)
#define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16)

+#define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1)
+
enum intel_pdi_type {
INTEL_PDI_IN = 0,
INTEL_PDI_OUT = 1,
@@ -922,7 +924,7 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus)
struct sdw_master_prop *prop = &bus->prop;
struct fwnode_handle *link;
char name[32];
- int nval, i;
+ u32 quirk_mask;

/* Find master handle */
snprintf(name, sizeof(name),
@@ -937,6 +939,14 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus)
fwnode_property_read_u32(link,
"intel-sdw-ip-clock",
&prop->mclk_freq);
+
+ fwnode_property_read_u32(link,
+ "intel-quirk-mask",
+ &quirk_mask);
+
+ if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
+ prop->hw_disabled = true;
+
return 0;
}

@@ -997,6 +1007,12 @@ static int intel_probe(struct platform_device *pdev)
goto err_master_reg;
}

+ if (sdw->cdns.bus.prop.hw_disabled) {
+ dev_info(&pdev->dev, "SoundWire master %d is disabled, ignoring\n",
+ sdw->cdns.bus.link_id);
+ return 0;
+ }
+
/* Initialize shim and controller */
intel_link_power_up(sdw);
intel_shim_init(sdw);
@@ -1050,9 +1066,11 @@ static int intel_remove(struct platform_device *pdev)

sdw = platform_get_drvdata(pdev);

- intel_debugfs_exit(sdw);
- free_irq(sdw->res->irq, sdw);
- snd_soc_unregister_component(sdw->cdns.dev);
+ if (!sdw->cdns.bus.prop.hw_disabled) {
+ intel_debugfs_exit(sdw);
+ free_irq(sdw->res->irq, sdw);
+ snd_soc_unregister_component(sdw->cdns.dev);
+ }
sdw_delete_bus_master(&sdw->cdns.bus);

return 0;
diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index c7dfc824be80..f78b076a8782 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -380,6 +380,7 @@ struct sdw_slave_prop {
* @err_threshold: Number of times that software may retry sending a single
* command
* @mclk_freq: clock reference passed to SoundWire Master, in Hz.
+ * @hw_disabled: if true, the Master is not functional, typically due to pin-mux
*/
struct sdw_master_prop {
u32 revision;
@@ -395,6 +396,7 @@ struct sdw_master_prop {
bool dynamic_frame;
u32 err_threshold;
u32 mclk_freq;
+ bool hw_disabled;
};

int sdw_master_read_prop(struct sdw_bus *bus);
--
2.20.1


2019-07-25 23:44:19

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 21/40] soundwire: export helpers to find row and column values

Add a prefix for common tables and export 2 helpers to set the frame
shapes based on row/col values.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/bus.h | 7 +++++--
drivers/soundwire/stream.c | 14 ++++++++------
2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
index 06ac4adb0074..c57c9c23f6ca 100644
--- a/drivers/soundwire/bus.h
+++ b/drivers/soundwire/bus.h
@@ -73,8 +73,11 @@ struct sdw_msg {

#define SDW_DOUBLE_RATE_FACTOR 2

-extern int rows[SDW_FRAME_ROWS];
-extern int cols[SDW_FRAME_COLS];
+extern int sdw_rows[SDW_FRAME_ROWS];
+extern int sdw_cols[SDW_FRAME_COLS];
+
+int sdw_find_row_index(int row);
+int sdw_find_col_index(int col);

/**
* sdw_port_runtime: Runtime port parameters for Master or Slave
diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
index a0476755a459..53f5e790fcd7 100644
--- a/drivers/soundwire/stream.c
+++ b/drivers/soundwire/stream.c
@@ -21,37 +21,39 @@
* The rows are arranged as per the array index value programmed
* in register. The index 15 has dummy value 0 in order to fill hole.
*/
-int rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,
+int sdw_rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,
96, 100, 120, 128, 150, 160, 250, 0,
192, 200, 240, 256, 72, 144, 90, 180};

-int cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};
+int sdw_cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};

-static int sdw_find_col_index(int col)
+int sdw_find_col_index(int col)
{
int i;

for (i = 0; i < SDW_FRAME_COLS; i++) {
- if (cols[i] == col)
+ if (sdw_cols[i] == col)
return i;
}

pr_warn("Requested column not found, selecting lowest column no: 2\n");
return 0;
}
+EXPORT_SYMBOL(sdw_find_col_index);

-static int sdw_find_row_index(int row)
+int sdw_find_row_index(int row)
{
int i;

for (i = 0; i < SDW_FRAME_ROWS; i++) {
- if (rows[i] == row)
+ if (sdw_rows[i] == row)
return i;
}

pr_warn("Requested row not found, selecting lowest row no: 48\n");
return 0;
}
+EXPORT_SYMBOL(sdw_find_row_index);

static int _sdw_program_slave_port_params(struct sdw_bus *bus,
struct sdw_slave *slave,
--
2.20.1


2019-07-25 23:44:20

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 19/40] soundwire: bus: improve dynamic debug comments for enumeration

update comments to provide better understanding of enumeration flows.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/bus.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index bca378806d00..2354675ef104 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -483,7 +483,8 @@ static int sdw_assign_device_num(struct sdw_slave *slave)

ret = sdw_write(slave, SDW_SCP_DEVNUMBER, dev_num);
if (ret < 0) {
- dev_err(&slave->dev, "Program device_num failed: %d\n", ret);
+ dev_err(&slave->dev, "Program device_num %d failed: %d\n",
+ dev_num, ret);
return ret;
}

@@ -540,6 +541,7 @@ static int sdw_program_device_num(struct sdw_bus *bus)
do {
ret = sdw_transfer(bus, &msg);
if (ret == -ENODATA) { /* end of device id reads */
+ dev_dbg(bus->dev, "No more devices to enumerate\n");
ret = 0;
break;
}
@@ -982,6 +984,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
int i, ret = 0;

if (status[0] == SDW_SLAVE_ATTACHED) {
+ dev_err(bus->dev, "Slave attached, programming device number\n");
ret = sdw_program_device_num(bus);
if (ret)
dev_err(bus->dev, "Slave attach failed: %d\n", ret);
--
2.20.1


2019-07-25 23:44:33

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 40/40] soundwire: intel: add delay on restart for enumeration

We have a conceptual issue on restart: the interaction with the slaves
can start before (re) enumeration is complete. Add a delay for now but
we will need to have an async notification that all devices are back
on the bus.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/intel.c | 5 +++++
1 file changed, 5 insertions(+)

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 1394a2322553..e4ea430b5a8e 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -1242,6 +1242,11 @@ static int intel_resume(struct device *dev)

ret = sdw_cdns_exit_reset(&sdw->cdns);

+ /* add delay to let Slaves re-enumerate */
+ usleep_range(20000, 30000);
+
+ dev_dbg(dev, "%s done\n", __func__);
+
return ret;
}

--
2.20.1


2019-07-25 23:44:34

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 38/40] soundwire: cadence_master: make clock stop exit configurable on init

The use of clock stop is not a requirement, the IP can e.g. be
completely power gated and not detect any wakes while in s2idle/deep
sleep.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 15 ++++++++-------
drivers/soundwire/cadence_master.h | 2 +-
drivers/soundwire/intel.c | 2 +-
3 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 53278aa2436f..4ab6f70d7705 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -1010,7 +1010,7 @@ static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
* sdw_cdns_init() - Cadence initialization
* @cdns: Cadence instance
*/
-int sdw_cdns_init(struct sdw_cdns *cdns)
+int sdw_cdns_init(struct sdw_cdns *cdns, bool clock_stop_exit)
{
struct sdw_bus *bus = &cdns->bus;
struct sdw_master_prop *prop = &bus->prop;
@@ -1018,12 +1018,13 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
int divider;
int ret;

- /* Exit clock stop */
- ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL,
- CDNS_MCP_CONTROL_CLK_STOP_CLR);
- if (ret < 0) {
- dev_err(cdns->dev, "Couldn't exit from clock stop\n");
- return ret;
+ if (clock_stop_exit) {
+ ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL,
+ CDNS_MCP_CONTROL_CLK_STOP_CLR);
+ if (ret < 0) {
+ dev_err(cdns->dev, "Couldn't exit from clock stop\n");
+ return ret;
+ }
}

/* Set clock divider */
diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
index 1a0ba36dd78f..091b771b570d 100644
--- a/drivers/soundwire/cadence_master.h
+++ b/drivers/soundwire/cadence_master.h
@@ -158,7 +158,7 @@ extern struct sdw_master_ops sdw_cdns_master_ops;
irqreturn_t sdw_cdns_irq(int irq, void *dev_id);
irqreturn_t sdw_cdns_thread(int irq, void *dev_id);

-int sdw_cdns_init(struct sdw_cdns *cdns);
+int sdw_cdns_init(struct sdw_cdns *cdns, bool clock_stop_exit);
int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
struct sdw_cdns_stream_config config);
int sdw_cdns_exit_reset(struct sdw_cdns *cdns);
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 1192d5775484..db7bf2912767 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -1043,7 +1043,7 @@ static int intel_init(struct sdw_intel *sdw)
intel_link_power_up(sdw);
intel_shim_init(sdw);

- return sdw_cdns_init(&sdw->cdns);
+ return sdw_cdns_init(&sdw->cdns, false);
}

/*
--
2.20.1


2019-07-25 23:44:34

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 22/40] soundwire: include mod_devicetable.h to avoid compiling warnings

From: Bard liao <[email protected]>

Reported-by: kbuild test robot <[email protected]>
Signed-off-by: Bard liao <[email protected]>
Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
include/linux/soundwire/sdw.h | 2 ++
1 file changed, 2 insertions(+)

diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index a49028e9d666..31d1e8acf25b 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -4,6 +4,8 @@
#ifndef __SOUNDWIRE_H
#define __SOUNDWIRE_H

+#include <linux/mod_devicetable.h>
+
struct sdw_bus;
struct sdw_slave;

--
2.20.1


2019-07-25 23:44:44

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 25/40] soundwire: intel: use BIOS information to set clock dividers

The BIOS provides an Intel-specific property, let's use it to avoid
hard-coded clock dividers.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 26 ++++++++++++++++++++++----
drivers/soundwire/intel.c | 26 ++++++++++++++++++++++++++
include/linux/soundwire/sdw.h | 2 ++
3 files changed, 50 insertions(+), 4 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index d84344e29f71..10ebcef2e84e 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -173,8 +173,6 @@
#define CDNS_PDI_CONFIG_PORT GENMASK(4, 0)

/* Driver defaults */
-
-#define CDNS_DEFAULT_CLK_DIVIDER 0
#define CDNS_DEFAULT_SSP_INTERVAL 0x18
#define CDNS_TX_TIMEOUT 2000

@@ -973,7 +971,10 @@ static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
*/
int sdw_cdns_init(struct sdw_cdns *cdns)
{
+ struct sdw_bus *bus = &cdns->bus;
+ struct sdw_master_prop *prop = &bus->prop;
u32 val;
+ int divider;
int ret;

/* Exit clock stop */
@@ -985,9 +986,17 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
}

/* Set clock divider */
+ divider = (prop->mclk_freq / prop->max_clk_freq) - 1;
val = cdns_readl(cdns, CDNS_MCP_CLK_CTRL0);
- val |= CDNS_DEFAULT_CLK_DIVIDER;
+ val |= divider;
cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
+ cdns_writel(cdns, CDNS_MCP_CLK_CTRL1, val);
+
+ pr_err("plb: mclk %d max_freq %d divider %d register %x\n",
+ prop->mclk_freq,
+ prop->max_clk_freq,
+ divider,
+ val);

/* Set the default frame shape */
val = cdns_set_default_frame_shape(prop->default_row,
@@ -1035,6 +1044,7 @@ EXPORT_SYMBOL(sdw_cdns_init);

int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
{
+ struct sdw_master_prop *prop = &bus->prop;
struct sdw_cdns *cdns = bus_to_cdns(bus);
int mcp_clkctrl_off, mcp_clkctrl;
int divider;
@@ -1044,7 +1054,9 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
return -EINVAL;
}

- divider = (params->max_dr_freq / params->curr_dr_freq) - 1;
+ divider = prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR /
+ params->curr_dr_freq;
+ divider--; /* divider is 1/(N+1) */

if (params->next_bank)
mcp_clkctrl_off = CDNS_MCP_CLK_CTRL1;
@@ -1055,6 +1067,12 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
mcp_clkctrl |= divider;
cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl);

+ pr_err("plb: mclk * 2 %d curr_dr_freq %d divider %d register %x\n",
+ prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR,
+ params->curr_dr_freq,
+ divider,
+ mcp_clkctrl);
+
return 0;
}
EXPORT_SYMBOL(cdns_bus_conf);
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index c718c9c67a37..796ac2bc8cea 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -917,11 +917,37 @@ static int intel_register_dai(struct sdw_intel *sdw)
dais, num_dai);
}

+static int sdw_master_read_intel_prop(struct sdw_bus *bus)
+{
+ struct sdw_master_prop *prop = &bus->prop;
+ struct fwnode_handle *link;
+ char name[32];
+ int nval, i;
+
+ /* Find master handle */
+ snprintf(name, sizeof(name),
+ "mipi-sdw-link-%d-subproperties", bus->link_id);
+
+ link = device_get_named_child_node(bus->dev, name);
+ if (!link) {
+ dev_err(bus->dev, "Master node %s not found\n", name);
+ return -EIO;
+ }
+
+ fwnode_property_read_u32(link,
+ "intel-sdw-ip-clock",
+ &prop->mclk_freq);
+ return 0;
+}
+
static int intel_prop_read(struct sdw_bus *bus)
{
/* Initialize with default handler to read all DisCo properties */
sdw_master_read_prop(bus);

+ /* read Intel-specific properties */
+ sdw_master_read_intel_prop(bus);
+
return 0;
}

diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
index 31d1e8acf25b..b6acc436ac80 100644
--- a/include/linux/soundwire/sdw.h
+++ b/include/linux/soundwire/sdw.h
@@ -379,6 +379,7 @@ struct sdw_slave_prop {
* @dynamic_frame: Dynamic frame shape supported
* @err_threshold: Number of times that software may retry sending a single
* command
+ * @mclk_freq: clock reference passed to SoundWire Master, in Hz.
*/
struct sdw_master_prop {
u32 revision;
@@ -393,6 +394,7 @@ struct sdw_master_prop {
u32 default_col;
bool dynamic_frame;
u32 err_threshold;
+ u32 mclk_freq;
};

int sdw_master_read_prop(struct sdw_bus *bus);
--
2.20.1


2019-07-25 23:44:50

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled

Not all platforms support runtime_pm for now, let's use runtime_pm
only when enabled.

Suggested-by: Srinivas Kandagatla <[email protected]>
Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/bus.c | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index 5ad4109dc72f..0a45dc5713df 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -332,12 +332,16 @@ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
if (ret < 0)
return ret;

- ret = pm_runtime_get_sync(slave->bus->dev);
- if (ret < 0)
- return ret;
+ if (pm_runtime_enabled(slave->bus->dev)) {
+ ret = pm_runtime_get_sync(slave->bus->dev);
+ if (ret < 0)
+ return ret;
+ }

ret = sdw_transfer(slave->bus, &msg);
- pm_runtime_put(slave->bus->dev);
+
+ if (pm_runtime_enabled(slave->bus->dev))
+ pm_runtime_put(slave->bus->dev);

return ret;
}
@@ -359,13 +363,16 @@ int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
slave->dev_num, SDW_MSG_FLAG_WRITE, val);
if (ret < 0)
return ret;
-
- ret = pm_runtime_get_sync(slave->bus->dev);
- if (ret < 0)
- return ret;
+ if (pm_runtime_enabled(slave->bus->dev)) {
+ ret = pm_runtime_get_sync(slave->bus->dev);
+ if (ret < 0)
+ return ret;
+ }

ret = sdw_transfer(slave->bus, &msg);
- pm_runtime_put(slave->bus->dev);
+
+ if (pm_runtime_enabled(slave->bus->dev))
+ pm_runtime_put(slave->bus->dev);

return ret;
}
--
2.20.1


2019-07-25 23:44:52

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 14/40] soundwire: cadence_master: fix definitions for INTSTAT0/1

Two off-by-one errors: INTSTAT0 missed BIT(31) and INTSTAT1 is only
defined on first 16 bits.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index d9d9e3d964dd..889fa2cd49ae 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -100,8 +100,8 @@
#define CDNS_MCP_SLAVE_INTMASK0 0x5C
#define CDNS_MCP_SLAVE_INTMASK1 0x60

-#define CDNS_MCP_SLAVE_INTMASK0_MASK GENMASK(30, 0)
-#define CDNS_MCP_SLAVE_INTMASK1_MASK GENMASK(16, 0)
+#define CDNS_MCP_SLAVE_INTMASK0_MASK GENMASK(31, 0)
+#define CDNS_MCP_SLAVE_INTMASK1_MASK GENMASK(15, 0)

#define CDNS_MCP_PORT_INTSTAT 0x64
#define CDNS_MCP_PDI_STAT 0x6C
--
2.20.1


2019-07-25 23:44:52

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 24/40] soundwire: cadence_master: use BIOS defaults for frame shape

Remove hard-coding and use BIOS values. If they are wrong use default
48x2 frame shape.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 442f78c00f09..d84344e29f71 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -175,7 +175,6 @@
/* Driver defaults */

#define CDNS_DEFAULT_CLK_DIVIDER 0
-#define CDNS_DEFAULT_FRAME_SHAPE 0x30
#define CDNS_DEFAULT_SSP_INTERVAL 0x18
#define CDNS_TX_TIMEOUT 2000

@@ -954,6 +953,20 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
}
EXPORT_SYMBOL(sdw_cdns_pdi_init);

+static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
+{
+ u32 val;
+ int c;
+ int r;
+
+ r = sdw_find_row_index(n_rows);
+ c = sdw_find_col_index(n_cols);
+
+ val = (r << 3) | c;
+
+ return val;
+}
+
/**
* sdw_cdns_init() - Cadence initialization
* @cdns: Cadence instance
@@ -977,7 +990,9 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);

/* Set the default frame shape */
- cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT, CDNS_DEFAULT_FRAME_SHAPE);
+ val = cdns_set_default_frame_shape(prop->default_row,
+ prop->default_col);
+ cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT, val);

/* Set SSP interval to default value */
cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, CDNS_DEFAULT_SSP_INTERVAL);
--
2.20.1


2019-07-25 23:44:53

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 16/40] soundwire: cadence_master: improve startup sequence with link hw_reset

Enable interrupts first, then engage hardware bus reset with maximum
duration to make sure the Slave(s) correctly detect the reset pattern
and to ensure electrical conflicts can be resolved.

Without these changes the initialization is randomly corrupted by bus
clashes, parity errors and Slave attachment does not generate any
interrupt, despite the status showing them being attached.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 35 +++++++++++++++++++++++++-----
1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 25d5c7267c15..442f78c00f09 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -778,6 +778,31 @@ EXPORT_SYMBOL(sdw_cdns_thread);
* init routines
*/

+static int do_reset(struct sdw_cdns *cdns)
+{
+ int ret;
+
+ /* program maximum length reset to be safe */
+ cdns_updatel(cdns, CDNS_MCP_CONTROL,
+ CDNS_MCP_CONTROL_RST_DELAY,
+ CDNS_MCP_CONTROL_RST_DELAY);
+
+ /* use hardware generated reset */
+ cdns_updatel(cdns, CDNS_MCP_CONTROL,
+ CDNS_MCP_CONTROL_HW_RST,
+ CDNS_MCP_CONTROL_HW_RST);
+
+ /* enable bus operations with clock and data */
+ cdns_updatel(cdns, CDNS_MCP_CONFIG,
+ CDNS_MCP_CONFIG_OP,
+ CDNS_MCP_CONFIG_OP_NORMAL);
+
+ /* commit changes */
+ ret = cdns_update_config(cdns);
+
+ return ret;
+}
+
/**
* sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
* @cdns: Cadence instance
@@ -809,7 +834,7 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)

cdns_writel(cdns, CDNS_MCP_INTMASK, mask);

- return 0;
+ return do_reset(cdns);
}
EXPORT_SYMBOL(sdw_cdns_enable_interrupt);

@@ -958,6 +983,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, CDNS_DEFAULT_SSP_INTERVAL);
cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, CDNS_DEFAULT_SSP_INTERVAL);

+ /* flush command FIFOs */
+ cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_RST,
+ CDNS_MCP_CONTROL_CMD_RST);
+
/* Set cmd accept mode */
cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT,
CDNS_MCP_CONTROL_CMD_ACCEPT);
@@ -980,10 +1009,6 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
/* Set cmd mode for Tx and Rx cmds */
val &= ~CDNS_MCP_CONFIG_CMD;

- /* Set operation to normal */
- val &= ~CDNS_MCP_CONFIG_OP;
- val |= CDNS_MCP_CONFIG_OP_NORMAL;
-
cdns_writel(cdns, CDNS_MCP_CONFIG, val);

/* commit changes */
--
2.20.1


2019-07-25 23:44:53

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 35/40] soundwire: intel: export helper to exit reset

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 9 +++++++--
drivers/soundwire/cadence_master.h | 1 +
drivers/soundwire/intel.c | 4 ++++
3 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 4a189e487830..f486fe15fb46 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -780,7 +780,11 @@ EXPORT_SYMBOL(sdw_cdns_thread);
* init routines
*/

-static int do_reset(struct sdw_cdns *cdns)
+/**
+ * sdw_cdns_exit_reset() - Program reset parameters and start bus operations
+ * @cdns: Cadence instance
+ */
+int sdw_cdns_exit_reset(struct sdw_cdns *cdns)
{
int ret;

@@ -804,6 +808,7 @@ static int do_reset(struct sdw_cdns *cdns)

return ret;
}
+EXPORT_SYMBOL(sdw_cdns_exit_reset);

/**
* sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
@@ -839,7 +844,7 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)

cdns_writel(cdns, CDNS_MCP_INTMASK, mask);

- return do_reset(cdns);
+ return 0;
}
EXPORT_SYMBOL(sdw_cdns_enable_interrupt);

diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
index de97bc22acb7..2b551f9226f3 100644
--- a/drivers/soundwire/cadence_master.h
+++ b/drivers/soundwire/cadence_master.h
@@ -161,6 +161,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
int sdw_cdns_init(struct sdw_cdns *cdns);
int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
struct sdw_cdns_stream_config config);
+int sdw_cdns_exit_reset(struct sdw_cdns *cdns);
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);

void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index a976480d6f36..9ebe38e4d979 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -1112,6 +1112,8 @@ static int intel_probe(struct platform_device *pdev)

ret = sdw_cdns_enable_interrupt(&sdw->cdns);

+ ret = sdw_cdns_exit_reset(&sdw->cdns);
+
/* Register DAIs */
ret = intel_register_dai(sdw);
if (ret) {
@@ -1199,6 +1201,8 @@ static int intel_resume(struct device *dev)

sdw_cdns_enable_interrupt(&sdw->cdns);

+ ret = sdw_cdns_exit_reset(&sdw->cdns);
+
return ret;
}

--
2.20.1


2019-07-25 23:44:57

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 12/40] soundwire: cadence_master: revisit interrupt settings

Adding missing interrupt masks (parity, etc) and missing checks.
Clarify which masks are for which usage.

Signed-off-by: Bard Liao <[email protected]>
Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index bdc3ed844829..0f3b9c160b01 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -76,9 +76,12 @@
#define CDNS_MCP_INT_DPINT BIT(11)
#define CDNS_MCP_INT_CTRL_CLASH BIT(10)
#define CDNS_MCP_INT_DATA_CLASH BIT(9)
+#define CDNS_MCP_INT_PARITY BIT(8)
#define CDNS_MCP_INT_CMD_ERR BIT(7)
+#define CDNS_MCP_INT_RX_NE BIT(3)
#define CDNS_MCP_INT_RX_WL BIT(2)
#define CDNS_MCP_INT_TXE BIT(1)
+#define CDNS_MCP_INT_TXF BIT(0)

#define CDNS_MCP_INTSET 0x4C

@@ -689,6 +692,11 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
}
}

+ if (int_status & CDNS_MCP_INT_PARITY) {
+ /* Parity error detected by Master */
+ dev_err_ratelimited(cdns->dev, "Parity error\n");
+ }
+
if (int_status & CDNS_MCP_INT_CTRL_CLASH) {
/* Slave is driving bit slot during control word */
dev_err_ratelimited(cdns->dev, "Bus clash for control word\n");
@@ -761,10 +769,21 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1,
CDNS_MCP_SLAVE_INTMASK1_MASK);

+ /* enable detection of slave state changes */
mask = CDNS_MCP_INT_SLAVE_RSVD | CDNS_MCP_INT_SLAVE_ALERT |
- CDNS_MCP_INT_SLAVE_ATTACH | CDNS_MCP_INT_SLAVE_NATTACH |
- CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
- CDNS_MCP_INT_RX_WL | CDNS_MCP_INT_IRQ | CDNS_MCP_INT_DPINT;
+ CDNS_MCP_INT_SLAVE_ATTACH | CDNS_MCP_INT_SLAVE_NATTACH;
+
+ /* enable detection of bus issues */
+ mask |= CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
+ CDNS_MCP_INT_PARITY;
+
+ /* no detection of port interrupts for now */
+
+ /* enable detection of RX fifo level */
+ mask |= CDNS_MCP_INT_RX_WL;
+
+ /* now enable all of the above */
+ mask |= CDNS_MCP_INT_IRQ;

cdns_writel(cdns, CDNS_MCP_INTMASK, mask);

--
2.20.1


2019-07-25 23:45:04

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 05/40] soundwire: intel: move interrupt enable after interrupt handler registration

Not sure why the existing code would enable interrupts without the
ability to deal with them.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/intel.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index aeadc341c0a3..68832e613b1e 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -981,8 +981,6 @@ static int intel_probe(struct platform_device *pdev)
if (ret)
goto err_init;

- ret = sdw_cdns_enable_interrupt(&sdw->cdns);
-
/* Read the PDI config and initialize cadence PDI */
intel_pdi_init(sdw, &config);
ret = sdw_cdns_pdi_init(&sdw->cdns, config);
@@ -1000,6 +998,8 @@ static int intel_probe(struct platform_device *pdev)
goto err_init;
}

+ ret = sdw_cdns_enable_interrupt(&sdw->cdns);
+
/* Register DAIs */
ret = intel_register_dai(sdw);
if (ret) {
--
2.20.1


2019-07-25 23:45:07

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 10/40] soundwire: cadence_master: remove useless wrapper

Now that we've removed the update config, there's no need for a wrapper.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index eb46cf651d62..e85e49340986 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -749,7 +749,12 @@ EXPORT_SYMBOL(sdw_cdns_thread);
/*
* init routines
*/
-static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
+
+/**
+ * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
+ * @cdns: Cadence instance
+ */
+int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
{
u32 mask;

@@ -767,17 +772,6 @@ static int _cdns_enable_interrupt(struct sdw_cdns *cdns)

return 0;
}
-
-/**
- * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
- * @cdns: Cadence instance
- */
-int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
-{
- _cdns_enable_interrupt(cdns);
-
- return 0;
-}
EXPORT_SYMBOL(sdw_cdns_enable_interrupt);

static int cdns_allocate_pdi(struct sdw_cdns *cdns,
--
2.20.1


2019-07-25 23:45:23

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 13/40] soundwire: cadence_master: fix register definition for SLAVE_STATE

wrong prefix and wrong macro.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index 0f3b9c160b01..d9d9e3d964dd 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -85,8 +85,8 @@

#define CDNS_MCP_INTSET 0x4C

-#define CDNS_SDW_SLAVE_STAT 0x50
-#define CDNS_MCP_SLAVE_STAT_MASK BIT(1, 0)
+#define CDNS_MCP_SLAVE_STAT 0x50
+#define CDNS_MCP_SLAVE_STAT_MASK GENMASK(1, 0)

#define CDNS_MCP_SLAVE_INTSTAT0 0x54
#define CDNS_MCP_SLAVE_INTSTAT1 0x58
--
2.20.1


2019-07-25 23:45:32

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 02/40] soundwire: cadence_master: add debugfs register dump

Add debugfs file to dump the Cadence master registers

Credits: this patch is based on an earlier internal contribution by
Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. The main change
is the use of scnprintf to avoid known issues with snprintf.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/cadence_master.c | 98 ++++++++++++++++++++++++++++++
drivers/soundwire/cadence_master.h | 2 +
2 files changed, 100 insertions(+)

diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
index ff4badc9b3de..91e8bacb83e3 100644
--- a/drivers/soundwire/cadence_master.c
+++ b/drivers/soundwire/cadence_master.c
@@ -8,6 +8,7 @@

#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/debugfs.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -223,6 +224,103 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value)
return -EAGAIN;
}

+/*
+ * debugfs
+ */
+
+#define RD_BUF (2 * PAGE_SIZE)
+
+static ssize_t cdns_sprintf(struct sdw_cdns *cdns,
+ char *buf, size_t pos, unsigned int reg)
+{
+ return scnprintf(buf + pos, RD_BUF - pos,
+ "%4x\t%4x\n", reg, cdns_readl(cdns, reg));
+}
+
+static ssize_t cdns_reg_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct sdw_cdns *cdns = file->private_data;
+ char *buf;
+ ssize_t ret;
+ int i, j;
+
+ buf = kzalloc(RD_BUF, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = scnprintf(buf, RD_BUF, "Register Value\n");
+ ret += scnprintf(buf + ret, RD_BUF - ret, "\nMCP Registers\n");
+ for (i = 0; i < 8; i++) /* 8 MCP registers */
+ ret += cdns_sprintf(cdns, buf, ret, i * 4);
+
+ ret += scnprintf(buf + ret, RD_BUF - ret,
+ "\nStatus & Intr Registers\n");
+ for (i = 0; i < 13; i++) /* 13 Status & Intr registers */
+ ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_STAT + i * 4);
+
+ ret += scnprintf(buf + ret, RD_BUF - ret,
+ "\nSSP & Clk ctrl Registers\n");
+ ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL0);
+ ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL1);
+ ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL0);
+ ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL1);
+
+ ret += scnprintf(buf + ret, RD_BUF - ret,
+ "\nDPn B0 Registers\n");
+ for (i = 0; i < 7; i++) {
+ ret += scnprintf(buf + ret, RD_BUF - ret,
+ "\nDP-%d\n", i);
+ for (j = 0; j < 6; j++)
+ ret += cdns_sprintf(cdns, buf, ret,
+ CDNS_DPN_B0_CONFIG(i) + j * 4);
+ }
+
+ ret += scnprintf(buf + ret, RD_BUF - ret,
+ "\nDPn B1 Registers\n");
+ for (i = 0; i < 7; i++) {
+ ret += scnprintf(buf + ret, RD_BUF - ret,
+ "\nDP-%d\n", i);
+
+ for (j = 0; j < 6; j++)
+ ret += cdns_sprintf(cdns, buf, ret,
+ CDNS_DPN_B1_CONFIG(i) + j * 4);
+ }
+
+ ret += scnprintf(buf + ret, RD_BUF - ret,
+ "\nDPn Control Registers\n");
+ for (i = 0; i < 7; i++)
+ ret += cdns_sprintf(cdns, buf, ret,
+ CDNS_PORTCTRL + i * CDNS_PORT_OFFSET);
+
+ ret += scnprintf(buf + ret, RD_BUF - ret,
+ "\nPDIn Config Registers\n");
+ for (i = 0; i < 7; i++)
+ ret += cdns_sprintf(cdns, buf, ret, CDNS_PDI_CONFIG(i));
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+ kfree(buf);
+
+ return ret;
+}
+
+static const struct file_operations cdns_reg_fops = {
+ .open = simple_open,
+ .read = cdns_reg_read,
+ .llseek = default_llseek,
+};
+
+/**
+ * sdw_cdns_debugfs_init() - Cadence debugfs init
+ * @cdns: Cadence instance
+ * @root: debugfs root
+ */
+void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root)
+{
+ debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);
+}
+EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init);
+
/*
* IO Calls
*/
diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
index fe2af62958b1..c0bf6ff00a44 100644
--- a/drivers/soundwire/cadence_master.h
+++ b/drivers/soundwire/cadence_master.h
@@ -163,6 +163,8 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
struct sdw_cdns_stream_config config);
int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);

+void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
+
int sdw_cdns_get_stream(struct sdw_cdns *cdns,
struct sdw_cdns_streams *stream,
u32 ch, u32 dir);
--
2.20.1


2019-07-25 23:46:26

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 08/40] soundwire: intel: remove BIOS work-arounds

the values passed by all existing BIOS are fine, let's use them as is.
The existing code must have been needed only on early prototypes.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/intel.c | 11 -----------
1 file changed, 11 deletions(-)

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 51990b192dc0..c718c9c67a37 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -922,17 +922,6 @@ static int intel_prop_read(struct sdw_bus *bus)
/* Initialize with default handler to read all DisCo properties */
sdw_master_read_prop(bus);

- /* BIOS is not giving some values correctly. So, lets override them */
- bus->prop.num_clk_freq = 1;
- bus->prop.clk_freq = devm_kcalloc(bus->dev, bus->prop.num_clk_freq,
- sizeof(*bus->prop.clk_freq),
- GFP_KERNEL);
- if (!bus->prop.clk_freq)
- return -ENOMEM;
-
- bus->prop.clk_freq[0] = bus->prop.max_clk_freq;
- bus->prop.err_threshold = 5;
-
return 0;
}

--
2.20.1


2019-07-25 23:46:33

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 07/40] soundwire: intel: fix channel number reported by hardware

PDI2 reports an invalid count, force the correct hardware-supported
value

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/intel.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 497879dd9c0d..51990b192dc0 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -401,6 +401,15 @@ intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm)

if (pcm) {
count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num));
+
+ /*
+ * TODO: pdi number 2 reports channel count as 1 even though
+ * it supports 8 channel. Performing hardcoding for pdi
+ * number 2.
+ */
+ if (pdi_num == 2)
+ count = 7;
+
} else {
count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
count = ((count & SDW_SHIM_PDMSCAP_CPSS) >>
--
2.20.1


2019-07-25 23:46:40

by Pierre-Louis Bossart

[permalink] [raw]
Subject: [RFC PATCH 06/40] soundwire: intel: prevent possible dereference in hw_params

This should not happen in production systems but we should test for
all callback arguments before invoking the config_stream callback.

Signed-off-by: Pierre-Louis Bossart <[email protected]>
---
drivers/soundwire/intel.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
index 68832e613b1e..497879dd9c0d 100644
--- a/drivers/soundwire/intel.c
+++ b/drivers/soundwire/intel.c
@@ -509,7 +509,7 @@ static int intel_config_stream(struct sdw_intel *sdw,
struct snd_soc_dai *dai,
struct snd_pcm_hw_params *hw_params, int link_id)
{
- if (sdw->res->ops && sdw->res->ops->config_stream)
+ if (sdw->res->ops && sdw->res->ops->config_stream && sdw->res->arg)
return sdw->res->ops->config_stream(sdw->res->arg,
substream, dai, hw_params, link_id);

--
2.20.1


2019-07-26 02:15:00

by Bard Liao

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 09/40] soundwire: cadence_master: fix usage of CONFIG_UPDATE

On 7/26/2019 7:40 AM, Pierre-Louis Bossart wrote:
> Per the hardware documentation, all changes to MCP_CONFIG,
> MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL need to be validated with a
> self-clearing write to MCP_CONFIG_UPDATE.
>
> For some reason, the existing code only does this write to
> CONFIG_UPDATE when enabling interrupts. Add a helper and do the update
> when the CONFIG is changed.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 29 +++++++++++++++++++++--------
> 1 file changed, 21 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 9f611a1fff0a..eb46cf651d62 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -224,6 +224,22 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value)
> return -EAGAIN;
> }
>
> +/*
> + * all changes to the MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL
> + * need to be confirmed with a write to MCP_CONFIG_UPDATE
> + */
> +static int cdns_update_config(struct sdw_cdns *cdns)
> +{
> + int ret;
> +
> + ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
> + CDNS_MCP_CONFIG_UPDATE_BIT);
> + if (ret < 0)
> + dev_err(cdns->dev, "Config update timedout\n");
> +
> + return ret;
> +}
> +
> /*
> * debugfs
> */
> @@ -758,15 +774,9 @@ static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
> */
> int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
> {
> - int ret;
> -
> _cdns_enable_interrupt(cdns);
> - ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
> - CDNS_MCP_CONFIG_UPDATE_BIT);
> - if (ret < 0)
> - dev_err(cdns->dev, "Config update timedout\n");
>
> - return ret;
Should we add cdns_update_config() here?
> + return 0;
> }
> EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
>
> @@ -943,7 +953,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
>
> cdns_writel(cdns, CDNS_MCP_CONFIG, val);
>
> - return 0;
> + /* commit changes */
> + ret = cdns_update_config(cdns);
> +
> + return ret;
> }
> EXPORT_SYMBOL(sdw_cdns_init);
>

2019-07-26 05:22:27

by Bard Liao

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 26/40] soundwire: cadence_master: fix divider setting in clock register


On 7/26/2019 7:40 AM, Pierre-Louis Bossart wrote:
> From: Rander Wang <[email protected]>
>
> The existing code uses an OR operation which would mix the original
> divider setting with the new one, resulting in an invalid
> configuration that can make codecs hang.
>
> Add the mask definition and use cdns_updatel to update divider
>
> Signed-off-by: Rander Wang <[email protected]>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 12 +++++++-----
> 1 file changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 10ebcef2e84e..18c6ac026e85 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -57,6 +57,7 @@
> #define CDNS_MCP_SSP_CTRL1 0x28
> #define CDNS_MCP_CLK_CTRL0 0x30
> #define CDNS_MCP_CLK_CTRL1 0x38
> +#define CDNS_MCP_CLK_MCLKD_MASK GENMASK(7, 0)
>
> #define CDNS_MCP_STAT 0x40
>
> @@ -988,9 +989,11 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
> /* Set clock divider */
> divider = (prop->mclk_freq / prop->max_clk_freq) - 1;
> val = cdns_readl(cdns, CDNS_MCP_CLK_CTRL0);


Do we still need to read cdns_readl(cdns, CDNS_MCP_CLK_CTRL0)

after this change?


> - val |= divider;
> - cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
> - cdns_writel(cdns, CDNS_MCP_CLK_CTRL1, val);
> +
> + cdns_updatel(cdns, CDNS_MCP_CLK_CTRL0,
> + CDNS_MCP_CLK_MCLKD_MASK, divider);
> + cdns_updatel(cdns, CDNS_MCP_CLK_CTRL1,
> + CDNS_MCP_CLK_MCLKD_MASK, divider);
>
> pr_err("plb: mclk %d max_freq %d divider %d register %x\n",
> prop->mclk_freq,
> @@ -1064,8 +1067,7 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
> mcp_clkctrl_off = CDNS_MCP_CLK_CTRL0;
>
> mcp_clkctrl = cdns_readl(cdns, mcp_clkctrl_off);


Same here.


> - mcp_clkctrl |= divider;
> - cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl);
> + cdns_updatel(cdns, mcp_clkctrl_off, CDNS_MCP_CLK_MCLKD_MASK, divider);
>
> pr_err("plb: mclk * 2 %d curr_dr_freq %d divider %d register %x\n",
> prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR,

2019-07-26 05:58:07

by rander.wang

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 26/40] soundwire: cadence_master: fix divider setting in clock register


在 7/26/2019 1:19 PM, Bard liao 写道:
>
> On 7/26/2019 7:40 AM, Pierre-Louis Bossart wrote:
>> From: Rander Wang <[email protected]>
>>
>> The existing code uses an OR operation which would mix the original
>> divider setting with the new one, resulting in an invalid
>> configuration that can make codecs hang.
>>
>> Add the mask definition and use cdns_updatel to update divider
>>
>> Signed-off-by: Rander Wang <[email protected]>
>> Signed-off-by: Pierre-Louis Bossart
>> <[email protected]>
>> ---
>>   drivers/soundwire/cadence_master.c | 12 +++++++-----
>>   1 file changed, 7 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/soundwire/cadence_master.c
>> b/drivers/soundwire/cadence_master.c
>> index 10ebcef2e84e..18c6ac026e85 100644
>> --- a/drivers/soundwire/cadence_master.c
>> +++ b/drivers/soundwire/cadence_master.c
>> @@ -57,6 +57,7 @@
>>   #define CDNS_MCP_SSP_CTRL1            0x28
>>   #define CDNS_MCP_CLK_CTRL0            0x30
>>   #define CDNS_MCP_CLK_CTRL1            0x38
>> +#define CDNS_MCP_CLK_MCLKD_MASK        GENMASK(7, 0)
>>     #define CDNS_MCP_STAT                0x40
>>   @@ -988,9 +989,11 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
>>       /* Set clock divider */
>>       divider    = (prop->mclk_freq / prop->max_clk_freq) - 1;
>>       val = cdns_readl(cdns, CDNS_MCP_CLK_CTRL0);
>
>
> Do we still need to read cdns_readl(cdns, CDNS_MCP_CLK_CTRL0)
>
> after this change?
>
The val is used to print debug message,  and my opinion is to change the log

from pr_err("plb: ........") to dev_dbg(bus->dev, "........") to follow
the dev_dbg

usage in this file.

>
>> -    val |= divider;
>> -    cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
>> -    cdns_writel(cdns, CDNS_MCP_CLK_CTRL1, val);
>> +
>> +    cdns_updatel(cdns, CDNS_MCP_CLK_CTRL0,
>> +             CDNS_MCP_CLK_MCLKD_MASK, divider);
>> +    cdns_updatel(cdns, CDNS_MCP_CLK_CTRL1,
>> +             CDNS_MCP_CLK_MCLKD_MASK, divider);
>>         pr_err("plb: mclk %d max_freq %d divider %d register %x\n",
>>              prop->mclk_freq,
>> @@ -1064,8 +1067,7 @@ int cdns_bus_conf(struct sdw_bus *bus, struct
>> sdw_bus_params *params)
>>           mcp_clkctrl_off = CDNS_MCP_CLK_CTRL0;
>>         mcp_clkctrl = cdns_readl(cdns, mcp_clkctrl_off);
>
>
> Same here.
>
Also refine the debug log.
>
>> -    mcp_clkctrl |= divider;
>> -    cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl);
>> +    cdns_updatel(cdns, mcp_clkctrl_off, CDNS_MCP_CLK_MCLKD_MASK,
>> divider);
>>         pr_err("plb: mclk * 2 %d curr_dr_freq %d divider %d register
>> %x\n",
>>              prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR,

2019-07-26 06:48:22

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 01/40] soundwire: add debugfs support

Hi Pierre,

A couple of nitpicks:

On Thu, Jul 25, 2019 at 06:39:53PM -0500, Pierre-Louis Bossart wrote:
> Add base debugfs mechanism for SoundWire bus by creating soundwire
> root and master-N and slave-x hierarchy.
>
> Also add SDW Slave SCP, DP0 and DP-N register debug file.
>
> Registers not implemented will print as "XX"
>
> Credits: this patch is based on an earlier internal contribution by
> Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. The main change
> is the use of scnprintf to avoid known issues with snprintf.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/Makefile | 4 +-
> drivers/soundwire/bus.c | 6 ++
> drivers/soundwire/bus.h | 24 ++++++
> drivers/soundwire/bus_type.c | 3 +
> drivers/soundwire/debugfs.c | 156 ++++++++++++++++++++++++++++++++++
> drivers/soundwire/slave.c | 1 +
> include/linux/soundwire/sdw.h | 4 +
> 7 files changed, 197 insertions(+), 1 deletion(-)
> create mode 100644 drivers/soundwire/debugfs.c

[snip]

> diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
> index 3048ca153f22..06ac4adb0074 100644
> --- a/drivers/soundwire/bus.h
> +++ b/drivers/soundwire/bus.h
> @@ -18,6 +18,30 @@ static inline int sdw_acpi_find_slaves(struct sdw_bus *bus)
> void sdw_extract_slave_id(struct sdw_bus *bus,
> u64 addr, struct sdw_slave_id *id);
>
> +#ifdef CONFIG_DEBUG_FS
> +struct dentry *sdw_bus_debugfs_init(struct sdw_bus *bus);
> +void sdw_bus_debugfs_exit(struct dentry *d);
> +struct dentry *sdw_slave_debugfs_init(struct sdw_slave *slave);
> +void sdw_slave_debugfs_exit(struct dentry *d);
> +void sdw_debugfs_init(void);
> +void sdw_debugfs_exit(void);
> +#else
> +struct dentry *sdw_bus_debugfs_init(struct sdw_bus *bus)
> +{ return NULL; }

static?

> +
> +void sdw_bus_debugfs_exit(struct dentry *d) {}
> +
> +struct dentry *sdw_slave_debugfs_init(struct sdw_slave *slave)
> +{ return NULL; }
> +
> +void sdw_slave_debugfs_exit(struct dentry *d) {}
> +
> +void sdw_debugfs_init(void) {}
> +
> +void sdw_debugfs_exit(void) {}

Same for all the above. You could also declare them inline, but I really hope
the compiler will be smart enough to do that itself.

> +
> +#endif
> +
> enum {
> SDW_MSG_FLAG_READ = 0,
> SDW_MSG_FLAG_WRITE,
> diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c
> index 2655602f0cfb..4a465f55039f 100644
> --- a/drivers/soundwire/bus_type.c
> +++ b/drivers/soundwire/bus_type.c
> @@ -6,6 +6,7 @@
> #include <linux/pm_domain.h>
> #include <linux/soundwire/sdw.h>
> #include <linux/soundwire/sdw_type.h>
> +#include "bus.h"
>
> /**
> * sdw_get_device_id - find the matching SoundWire device id
> @@ -177,11 +178,13 @@ EXPORT_SYMBOL_GPL(sdw_unregister_driver);
>
> static int __init sdw_bus_init(void)
> {
> + sdw_debugfs_init();
> return bus_register(&sdw_bus_type);
> }
>
> static void __exit sdw_bus_exit(void)
> {
> + sdw_debugfs_exit();
> bus_unregister(&sdw_bus_type);
> }
>
> diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c
> new file mode 100644
> index 000000000000..8d86e100516e
> --- /dev/null
> +++ b/drivers/soundwire/debugfs.c
> @@ -0,0 +1,156 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> +// Copyright(c) 2017-19 Intel Corporation.
> +
> +#include <linux/device.h>
> +#include <linux/debugfs.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/slab.h>
> +#include <linux/soundwire/sdw.h>
> +#include <linux/soundwire/sdw_registers.h>
> +#include "bus.h"
> +
> +#ifdef CONFIG_DEBUG_FS
> +struct dentry *sdw_debugfs_root;
> +#endif
> +
> +struct dentry *sdw_bus_debugfs_init(struct sdw_bus *bus)
> +{
> + struct dentry *d;

I would remove the above

> + char name[16];
> +
> + if (!sdw_debugfs_root)
> + return NULL;
> +
> + /* create the debugfs master-N */
> + snprintf(name, sizeof(name), "master-%d", bus->link_id);
> + d = debugfs_create_dir(name, sdw_debugfs_root);
> +
> + return d;

And just do

+ return debugfs_create_dir(name, sdw_debugfs_root);

> +}
> +
> +void sdw_bus_debugfs_exit(struct dentry *d)
> +{
> + debugfs_remove_recursive(d);
> +}
> +
> +#define RD_BUF (3 * PAGE_SIZE)
> +
> +static ssize_t sdw_sprintf(struct sdw_slave *slave,
> + char *buf, size_t pos, unsigned int reg)
> +{
> + int value;
> +
> + value = sdw_read(slave, reg);

I personally would join the two lines above, but that's just a personal
preference.

> +
> + if (value < 0)
> + return scnprintf(buf + pos, RD_BUF - pos, "%3x\tXX\n", reg);
> + else

I think it's advised to not use an else in such cases.

Thanks
Guennadi

> + return scnprintf(buf + pos, RD_BUF - pos,
> + "%3x\t%2x\n", reg, value);
> +}
> +
> +static ssize_t sdw_slave_reg_read(struct file *file, char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + struct sdw_slave *slave = file->private_data;
> + unsigned int reg;
> + char *buf;
> + ssize_t ret;
> + int i, j;
> +
> + buf = kzalloc(RD_BUF, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + ret = scnprintf(buf, RD_BUF, "Register Value\n");
> + ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP0\n");
> +
> + for (i = 0; i < 6; i++)
> + ret += sdw_sprintf(slave, buf, ret, i);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
> + ret += sdw_sprintf(slave, buf, ret, SDW_DP0_CHANNELEN);
> + for (i = SDW_DP0_SAMPLECTRL1; i <= SDW_DP0_LANECTRL; i++)
> + ret += sdw_sprintf(slave, buf, ret, i);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
> + ret += sdw_sprintf(slave, buf, ret,
> + SDW_DP0_CHANNELEN + SDW_BANK1_OFFSET);
> + for (i = SDW_DP0_SAMPLECTRL1 + SDW_BANK1_OFFSET;
> + i <= SDW_DP0_LANECTRL + SDW_BANK1_OFFSET; i++)
> + ret += sdw_sprintf(slave, buf, ret, i);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "\nSCP\n");
> + for (i = SDW_SCP_INT1; i <= SDW_SCP_BANKDELAY; i++)
> + ret += sdw_sprintf(slave, buf, ret, i);
> + for (i = SDW_SCP_DEVID_0; i <= SDW_SCP_DEVID_5; i++)
> + ret += sdw_sprintf(slave, buf, ret, i);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
> + ret += sdw_sprintf(slave, buf, ret, SDW_SCP_FRAMECTRL_B0);
> + ret += sdw_sprintf(slave, buf, ret, SDW_SCP_NEXTFRAME_B0);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
> + ret += sdw_sprintf(slave, buf, ret, SDW_SCP_FRAMECTRL_B1);
> + ret += sdw_sprintf(slave, buf, ret, SDW_SCP_NEXTFRAME_B1);
> +
> + for (i = 1; i < 14; i++) {
> + ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP%d\n", i);
> + reg = SDW_DPN_INT(i);
> + for (j = 0; j < 6; j++)
> + ret += sdw_sprintf(slave, buf, ret, reg + j);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
> + reg = SDW_DPN_CHANNELEN_B0(i);
> + for (j = 0; j < 9; j++)
> + ret += sdw_sprintf(slave, buf, ret, reg + j);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
> + reg = SDW_DPN_CHANNELEN_B1(i);
> + for (j = 0; j < 9; j++)
> + ret += sdw_sprintf(slave, buf, ret, reg + j);
> + }
> +
> + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> + kfree(buf);
> +
> + return ret;
> +}
> +
> +static const struct file_operations sdw_slave_reg_fops = {
> + .open = simple_open,
> + .read = sdw_slave_reg_read,
> + .llseek = default_llseek,
> +};
> +
> +struct dentry *sdw_slave_debugfs_init(struct sdw_slave *slave)
> +{
> + struct dentry *master;
> + struct dentry *d;
> + char name[32];
> +
> + master = slave->bus->debugfs;
> +
> + /* create the debugfs slave-name */
> + snprintf(name, sizeof(name), "%s", dev_name(&slave->dev));
> + d = debugfs_create_dir(name, master);
> +
> + debugfs_create_file("registers", 0400, d, slave, &sdw_slave_reg_fops);
> +
> + return d;
> +}
> +
> +void sdw_slave_debugfs_exit(struct dentry *d)
> +{
> + debugfs_remove_recursive(d);
> +}
> +
> +void sdw_debugfs_init(void)
> +{
> + sdw_debugfs_root = debugfs_create_dir("soundwire", NULL);
> +}
> +
> +void sdw_debugfs_exit(void)
> +{
> + debugfs_remove_recursive(sdw_debugfs_root);
> +}
> diff --git a/drivers/soundwire/slave.c b/drivers/soundwire/slave.c
> index f39a5815e25d..34d8bb995f45 100644
> --- a/drivers/soundwire/slave.c
> +++ b/drivers/soundwire/slave.c
> @@ -56,6 +56,7 @@ static int sdw_slave_add(struct sdw_bus *bus,
> mutex_unlock(&bus->bus_lock);
> put_device(&slave->dev);
> }
> + slave->debugfs = sdw_slave_debugfs_init(slave);
>
> return ret;
> }
> diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
> index 3b231472464a..a49028e9d666 100644
> --- a/include/linux/soundwire/sdw.h
> +++ b/include/linux/soundwire/sdw.h
> @@ -544,6 +544,7 @@ struct sdw_slave_ops {
> * @bus: Bus handle
> * @ops: Slave callback ops
> * @prop: Slave properties
> + * @debugfs: Slave debugfs
> * @node: node for bus list
> * @port_ready: Port ready completion flag for each Slave port
> * @dev_num: Device Number assigned by Bus
> @@ -555,6 +556,7 @@ struct sdw_slave {
> struct sdw_bus *bus;
> const struct sdw_slave_ops *ops;
> struct sdw_slave_prop prop;
> + struct dentry *debugfs;
> struct list_head node;
> struct completion *port_ready;
> u16 dev_num;
> @@ -731,6 +733,7 @@ struct sdw_master_ops {
> * @m_rt_list: List of Master instance of all stream(s) running on Bus. This
> * is used to compute and program bus bandwidth, clock, frame shape,
> * transport and port parameters
> + * @debugfs: Bus debugfs
> * @defer_msg: Defer message
> * @clk_stop_timeout: Clock stop timeout computed
> * @bank_switch_timeout: Bank switch timeout computed
> @@ -750,6 +753,7 @@ struct sdw_bus {
> struct sdw_bus_params params;
> struct sdw_master_prop prop;
> struct list_head m_rt_list;
> + struct dentry *debugfs;
> struct sdw_defer defer_msg;
> unsigned int clk_stop_timeout;
> u32 bank_switch_timeout;
> --
> 2.20.1
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 06:56:32

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 09/40] soundwire: cadence_master: fix usage of CONFIG_UPDATE

On Thu, Jul 25, 2019 at 06:40:01PM -0500, Pierre-Louis Bossart wrote:
> Per the hardware documentation, all changes to MCP_CONFIG,
> MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL need to be validated with a
> self-clearing write to MCP_CONFIG_UPDATE.
>
> For some reason, the existing code only does this write to
> CONFIG_UPDATE when enabling interrupts. Add a helper and do the update
> when the CONFIG is changed.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 29 +++++++++++++++++++++--------
> 1 file changed, 21 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 9f611a1fff0a..eb46cf651d62 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -224,6 +224,22 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value)
> return -EAGAIN;
> }
>
> +/*
> + * all changes to the MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL
> + * need to be confirmed with a write to MCP_CONFIG_UPDATE
> + */
> +static int cdns_update_config(struct sdw_cdns *cdns)
> +{
> + int ret;
> +
> + ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
> + CDNS_MCP_CONFIG_UPDATE_BIT);
> + if (ret < 0)
> + dev_err(cdns->dev, "Config update timedout\n");
> +
> + return ret;
> +}
> +
> /*
> * debugfs
> */
> @@ -758,15 +774,9 @@ static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
> */
> int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
> {
> - int ret;
> -
> _cdns_enable_interrupt(cdns);
> - ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
> - CDNS_MCP_CONFIG_UPDATE_BIT);
> - if (ret < 0)
> - dev_err(cdns->dev, "Config update timedout\n");
>
> - return ret;
> + return 0;
> }
> EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
>
> @@ -943,7 +953,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
>
> cdns_writel(cdns, CDNS_MCP_CONFIG, val);
>
> - return 0;
> + /* commit changes */
> + ret = cdns_update_config(cdns);
> +
> + return ret;

+ return cdns_update_config(cdns);

Thanks
Guennadi

> }
> EXPORT_SYMBOL(sdw_cdns_init);
>
> --
> 2.20.1
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 07:02:57

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 15/40] soundwire: cadence_master: handle multiple status reports per Slave

On Thu, Jul 25, 2019 at 06:40:07PM -0500, Pierre-Louis Bossart wrote:
> When a Slave reports multiple status in the sticky bits, find the
> latest configuration from the mirror of the PING frame status and
> update the status directly.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 34 ++++++++++++++++++++++++------
> 1 file changed, 28 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 889fa2cd49ae..25d5c7267c15 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -643,13 +643,35 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
>
> /* first check if Slave reported multiple status */
> if (set_status > 1) {
> + u32 val;
> +
> dev_warn_ratelimited(cdns->dev,
> - "Slave reported multiple Status: %d\n",
> - mask);
> - /*
> - * TODO: we need to reread the status here by
> - * issuing a PING cmd
> - */
> + "Slave %d reported multiple Status: %d\n",
> + i, mask);
> +
> + /* re-check latest status extracted from PING commands */
> + val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
> + val >>= (i * 2);

Superfluous parentheses.

> +
> + switch (val & 0x3) {
> + case 0:
> + status[i] = SDW_SLAVE_UNATTACHED;
> + break;
> + case 1:
> + status[i] = SDW_SLAVE_ATTACHED;
> + break;
> + case 2:
> + status[i] = SDW_SLAVE_ALERT;
> + break;
> + default:

There aren't many values left for the "default" case :-) But I'm not sure whether
any of

+ case 3:

or

+ case 3:
+ default:

would improve readability.

Thanks
Guennadi

> + status[i] = SDW_SLAVE_RESERVED;
> + break;
> + }
> +
> + dev_warn_ratelimited(cdns->dev,
> + "Slave %d status updated to %d\n",
> + i, status[i]);
> +
> }
> }
>
> --
> 2.20.1
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 07:23:54

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 16/40] soundwire: cadence_master: improve startup sequence with link hw_reset

On Thu, Jul 25, 2019 at 06:40:08PM -0500, Pierre-Louis Bossart wrote:
> Enable interrupts first, then engage hardware bus reset with maximum
> duration to make sure the Slave(s) correctly detect the reset pattern
> and to ensure electrical conflicts can be resolved.
>
> Without these changes the initialization is randomly corrupted by bus
> clashes, parity errors and Slave attachment does not generate any
> interrupt, despite the status showing them being attached.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 35 +++++++++++++++++++++++++-----
> 1 file changed, 30 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 25d5c7267c15..442f78c00f09 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -778,6 +778,31 @@ EXPORT_SYMBOL(sdw_cdns_thread);
> * init routines
> */
>
> +static int do_reset(struct sdw_cdns *cdns)
> +{
> + int ret;
> +
> + /* program maximum length reset to be safe */
> + cdns_updatel(cdns, CDNS_MCP_CONTROL,
> + CDNS_MCP_CONTROL_RST_DELAY,
> + CDNS_MCP_CONTROL_RST_DELAY);
> +
> + /* use hardware generated reset */
> + cdns_updatel(cdns, CDNS_MCP_CONTROL,
> + CDNS_MCP_CONTROL_HW_RST,
> + CDNS_MCP_CONTROL_HW_RST);
> +
> + /* enable bus operations with clock and data */
> + cdns_updatel(cdns, CDNS_MCP_CONFIG,
> + CDNS_MCP_CONFIG_OP,
> + CDNS_MCP_CONFIG_OP_NORMAL);
> +
> + /* commit changes */
> + ret = cdns_update_config(cdns);
> +
> + return ret;

+ return cdns_update_config(cdns);

and remove the "ret" variable.

Thanks
Guennadi

> +}
> +
> /**
> * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
> * @cdns: Cadence instance
> @@ -809,7 +834,7 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
>
> cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
>
> - return 0;
> + return do_reset(cdns);
> }
> EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
>
> @@ -958,6 +983,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
> cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, CDNS_DEFAULT_SSP_INTERVAL);
> cdns_writel(cdns, CDNS_MCP_SSP_CTRL1, CDNS_DEFAULT_SSP_INTERVAL);
>
> + /* flush command FIFOs */
> + cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_RST,
> + CDNS_MCP_CONTROL_CMD_RST);
> +
> /* Set cmd accept mode */
> cdns_updatel(cdns, CDNS_MCP_CONTROL, CDNS_MCP_CONTROL_CMD_ACCEPT,
> CDNS_MCP_CONTROL_CMD_ACCEPT);
> @@ -980,10 +1009,6 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
> /* Set cmd mode for Tx and Rx cmds */
> val &= ~CDNS_MCP_CONFIG_CMD;
>
> - /* Set operation to normal */
> - val &= ~CDNS_MCP_CONFIG_OP;
> - val |= CDNS_MCP_CONFIG_OP_NORMAL;
> -
> cdns_writel(cdns, CDNS_MCP_CONFIG, val);
>
> /* commit changes */
> --
> 2.20.1
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 07:40:29

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled

Hi Pierre,

I might be wrong but this doesn't seem right to me. (Supposedly) all RT-PM
functions check for "enabled" internally. The only thing that can happen is
that if RT-PM isn't enabled some of those functions will return an error.
So, in those cases where the return value of RT-PM functions isn't checked,
I don't think you need to do anything. Where it is checked maybe do

+ if (ret < 0 && pm_runtime_enabled(slave->bus->dev))

Thanks
Guennadi

On Thu, Jul 25, 2019 at 06:40:09PM -0500, Pierre-Louis Bossart wrote:
> Not all platforms support runtime_pm for now, let's use runtime_pm
> only when enabled.
>
> Suggested-by: Srinivas Kandagatla <[email protected]>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/bus.c | 25 ++++++++++++++++---------
> 1 file changed, 16 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
> index 5ad4109dc72f..0a45dc5713df 100644
> --- a/drivers/soundwire/bus.c
> +++ b/drivers/soundwire/bus.c
> @@ -332,12 +332,16 @@ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
> if (ret < 0)
> return ret;
>
> - ret = pm_runtime_get_sync(slave->bus->dev);
> - if (ret < 0)
> - return ret;
> + if (pm_runtime_enabled(slave->bus->dev)) {
> + ret = pm_runtime_get_sync(slave->bus->dev);
> + if (ret < 0)
> + return ret;
> + }
>
> ret = sdw_transfer(slave->bus, &msg);
> - pm_runtime_put(slave->bus->dev);
> +
> + if (pm_runtime_enabled(slave->bus->dev))
> + pm_runtime_put(slave->bus->dev);
>
> return ret;
> }
> @@ -359,13 +363,16 @@ int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
> slave->dev_num, SDW_MSG_FLAG_WRITE, val);
> if (ret < 0)
> return ret;
> -
> - ret = pm_runtime_get_sync(slave->bus->dev);
> - if (ret < 0)
> - return ret;
> + if (pm_runtime_enabled(slave->bus->dev)) {
> + ret = pm_runtime_get_sync(slave->bus->dev);
> + if (ret < 0)
> + return ret;
> + }
>
> ret = sdw_transfer(slave->bus, &msg);
> - pm_runtime_put(slave->bus->dev);
> +
> + if (pm_runtime_enabled(slave->bus->dev))
> + pm_runtime_put(slave->bus->dev);
>
> return ret;
> }
> --
> 2.20.1
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 07:50:18

by Jan Kotas

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled

Hello,

I while back I proposed a patch for this, but it went nowhere.

https://patchwork.kernel.org/patch/10887405/
Maybe something similar can be implemented?

Jan

> On 26 Jul 2019, at 09:39, Guennadi Liakhovetski <[email protected]> wrote:
>
> EXTERNAL MAIL
>
>
> Hi Pierre,
>
> I might be wrong but this doesn't seem right to me. (Supposedly) all RT-PM
> functions check for "enabled" internally. The only thing that can happen is
> that if RT-PM isn't enabled some of those functions will return an error.
> So, in those cases where the return value of RT-PM functions isn't checked,
> I don't think you need to do anything. Where it is checked maybe do
>
> + if (ret < 0 && pm_runtime_enabled(slave->bus->dev))
>
> Thanks
> Guennadi
>
> On Thu, Jul 25, 2019 at 06:40:09PM -0500, Pierre-Louis Bossart wrote:
>> Not all platforms support runtime_pm for now, let's use runtime_pm
>> only when enabled.
>>
>> Suggested-by: Srinivas Kandagatla <[email protected]>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/bus.c | 25 ++++++++++++++++---------
>> 1 file changed, 16 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
>> index 5ad4109dc72f..0a45dc5713df 100644
>> --- a/drivers/soundwire/bus.c
>> +++ b/drivers/soundwire/bus.c
>> @@ -332,12 +332,16 @@ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
>> if (ret < 0)
>> return ret;
>>
>> - ret = pm_runtime_get_sync(slave->bus->dev);
>> - if (ret < 0)
>> - return ret;
>> + if (pm_runtime_enabled(slave->bus->dev)) {
>> + ret = pm_runtime_get_sync(slave->bus->dev);
>> + if (ret < 0)
>> + return ret;
>> + }
>>
>> ret = sdw_transfer(slave->bus, &msg);
>> - pm_runtime_put(slave->bus->dev);
>> +
>> + if (pm_runtime_enabled(slave->bus->dev))
>> + pm_runtime_put(slave->bus->dev);
>>
>> return ret;
>> }
>> @@ -359,13 +363,16 @@ int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
>> slave->dev_num, SDW_MSG_FLAG_WRITE, val);
>> if (ret < 0)
>> return ret;
>> -
>> - ret = pm_runtime_get_sync(slave->bus->dev);
>> - if (ret < 0)
>> - return ret;
>> + if (pm_runtime_enabled(slave->bus->dev)) {
>> + ret = pm_runtime_get_sync(slave->bus->dev);
>> + if (ret < 0)
>> + return ret;
>> + }
>>
>> ret = sdw_transfer(slave->bus, &msg);
>> - pm_runtime_put(slave->bus->dev);
>> +
>> + if (pm_runtime_enabled(slave->bus->dev))
>> + pm_runtime_put(slave->bus->dev);
>>
>> return ret;
>> }
>> --
>> 2.20.1
>>
>> _______________________________________________
>> Alsa-devel mailing list
>> [email protected]
>> https://urldefense.proofpoint.com/v2/url?u=https-3A__mailman.alsa-2Dproject.org_mailman_listinfo_alsa-2Ddevel&d=DwIBAg&c=aUq983L2pue2FqKFoP6PGHMJQyoJ7kl3s3GZ-_haXqY&r=g7GAQENVXx_RQdyXHInPMg&m=vETGQLSPeGb7K_ZsXv4Tl3VFfdXzyummTDga97ozJcg&s=LiW4SToh5U0zhnkox54oRhJ1u3vFNbBB9nmzRDuCDjI&e=


2019-07-26 08:25:37

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled

Hi Jan,

On Fri, Jul 26, 2019 at 07:47:04AM +0000, Jan Kotas wrote:
> Hello,
>
> I while back I proposed a patch for this, but it went nowhere.
>
> https://patchwork.kernel.org/patch/10887405/
> Maybe something similar can be implemented?

Yes, I was thinking about checkint -EACCESS too, but then I noticed this code
in rpm_resume():

else if (dev->power.disable_depth == 1 && dev->power.is_suspended
&& dev->power.runtime_status == RPM_ACTIVE)
retval = 1;

i.e. if RT-PM is disabled on the device (but only exactly once?..) and it's
active and the device is suspended for a system suspend, the function will
return 1. I don't understand the logic of this code, but it seems to me it
could break the -EACCESS check?

Thanks
Guennadi

> Jan
>
> > On 26 Jul 2019, at 09:39, Guennadi Liakhovetski <[email protected]> wrote:
> >
> > EXTERNAL MAIL
> >
> >
> > Hi Pierre,
> >
> > I might be wrong but this doesn't seem right to me. (Supposedly) all RT-PM
> > functions check for "enabled" internally. The only thing that can happen is
> > that if RT-PM isn't enabled some of those functions will return an error.
> > So, in those cases where the return value of RT-PM functions isn't checked,
> > I don't think you need to do anything. Where it is checked maybe do
> >
> > + if (ret < 0 && pm_runtime_enabled(slave->bus->dev))
> >
> > Thanks
> > Guennadi
> >
> > On Thu, Jul 25, 2019 at 06:40:09PM -0500, Pierre-Louis Bossart wrote:
> >> Not all platforms support runtime_pm for now, let's use runtime_pm
> >> only when enabled.
> >>
> >> Suggested-by: Srinivas Kandagatla <[email protected]>
> >> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> >> ---
> >> drivers/soundwire/bus.c | 25 ++++++++++++++++---------
> >> 1 file changed, 16 insertions(+), 9 deletions(-)
> >>
> >> diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
> >> index 5ad4109dc72f..0a45dc5713df 100644
> >> --- a/drivers/soundwire/bus.c
> >> +++ b/drivers/soundwire/bus.c
> >> @@ -332,12 +332,16 @@ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
> >> if (ret < 0)
> >> return ret;
> >>
> >> - ret = pm_runtime_get_sync(slave->bus->dev);
> >> - if (ret < 0)
> >> - return ret;
> >> + if (pm_runtime_enabled(slave->bus->dev)) {
> >> + ret = pm_runtime_get_sync(slave->bus->dev);
> >> + if (ret < 0)
> >> + return ret;
> >> + }
> >>
> >> ret = sdw_transfer(slave->bus, &msg);
> >> - pm_runtime_put(slave->bus->dev);
> >> +
> >> + if (pm_runtime_enabled(slave->bus->dev))
> >> + pm_runtime_put(slave->bus->dev);
> >>
> >> return ret;
> >> }
> >> @@ -359,13 +363,16 @@ int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
> >> slave->dev_num, SDW_MSG_FLAG_WRITE, val);
> >> if (ret < 0)
> >> return ret;
> >> -
> >> - ret = pm_runtime_get_sync(slave->bus->dev);
> >> - if (ret < 0)
> >> - return ret;
> >> + if (pm_runtime_enabled(slave->bus->dev)) {
> >> + ret = pm_runtime_get_sync(slave->bus->dev);
> >> + if (ret < 0)
> >> + return ret;
> >> + }
> >>
> >> ret = sdw_transfer(slave->bus, &msg);
> >> - pm_runtime_put(slave->bus->dev);
> >> +
> >> + if (pm_runtime_enabled(slave->bus->dev))
> >> + pm_runtime_put(slave->bus->dev);
> >>
> >> return ret;
> >> }
> >> --
> >> 2.20.1
> >>
> >> _______________________________________________
> >> Alsa-devel mailing list
> >> [email protected]
> >> https://urldefense.proofpoint.com/v2/url?u=https-3A__mailman.alsa-2Dproject.org_mailman_listinfo_alsa-2Ddevel&d=DwIBAg&c=aUq983L2pue2FqKFoP6PGHMJQyoJ7kl3s3GZ-_haXqY&r=g7GAQENVXx_RQdyXHInPMg&m=vETGQLSPeGb7K_ZsXv4Tl3VFfdXzyummTDga97ozJcg&s=LiW4SToh5U0zhnkox54oRhJ1u3vFNbBB9nmzRDuCDjI&e=
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 08:34:52

by Jan Kotas

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled



> On 26 Jul 2019, at 10:22, Guennadi Liakhovetski <[email protected]> wrote:
>
> EXTERNAL MAIL
>
>
> Hi Jan,
>
> On Fri, Jul 26, 2019 at 07:47:04AM +0000, Jan Kotas wrote:
>> Hello,
>>
>> I while back I proposed a patch for this, but it went nowhere.
>>
>> https://urldefense.proofpoint.com/v2/url?u=https-3A__patchwork.kernel.org_patch_10887405_&d=DwIBAg&c=aUq983L2pue2FqKFoP6PGHMJQyoJ7kl3s3GZ-_haXqY&r=g7GAQENVXx_RQdyXHInPMg&m=i_0S359hFIVqNgv3fR5_MNzDOHP99trdXszZ-FMiQEE&s=ddktFZYlePh-bC7kXeoKWt4QomupzHATK4FLY4oSWKA&e=
>> Maybe something similar can be implemented?
>
> Yes, I was thinking about checkint -EACCESS too, but then I noticed this code
> in rpm_resume():
>
> else if (dev->power.disable_depth == 1 && dev->power.is_suspended
> && dev->power.runtime_status == RPM_ACTIVE)
> retval = 1;
>
> i.e. if RT-PM is disabled on the device (but only exactly once?..) and it's
> active and the device is suspended for a system suspend, the function will
> return 1. I don't understand the logic of this code, but it seems to me it
> could break the -EACCESS check?
>

Hi,

In such case ret < 0 will not be true, which I think is fine,
if I’m understanding you correctly.

Regards,
Jan


> Thanks
> Guennadi
>
>> Jan
>>
>>> On 26 Jul 2019, at 09:39, Guennadi Liakhovetski <[email protected]> wrote:
>>>
>>> EXTERNAL MAIL
>>>
>>>
>>> Hi Pierre,
>>>
>>> I might be wrong but this doesn't seem right to me. (Supposedly) all RT-PM
>>> functions check for "enabled" internally. The only thing that can happen is
>>> that if RT-PM isn't enabled some of those functions will return an error.
>>> So, in those cases where the return value of RT-PM functions isn't checked,
>>> I don't think you need to do anything. Where it is checked maybe do
>>>
>>> + if (ret < 0 && pm_runtime_enabled(slave->bus->dev))
>>>
>>> Thanks
>>> Guennadi
>>>
>>> On Thu, Jul 25, 2019 at 06:40:09PM -0500, Pierre-Louis Bossart wrote:
>>>> Not all platforms support runtime_pm for now, let's use runtime_pm
>>>> only when enabled.
>>>>
>>>> Suggested-by: Srinivas Kandagatla <[email protected]>
>>>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>>>> ---
>>>> drivers/soundwire/bus.c | 25 ++++++++++++++++---------
>>>> 1 file changed, 16 insertions(+), 9 deletions(-)
>>>>
>>>> diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
>>>> index 5ad4109dc72f..0a45dc5713df 100644
>>>> --- a/drivers/soundwire/bus.c
>>>> +++ b/drivers/soundwire/bus.c
>>>> @@ -332,12 +332,16 @@ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
>>>> if (ret < 0)
>>>> return ret;
>>>>
>>>> - ret = pm_runtime_get_sync(slave->bus->dev);
>>>> - if (ret < 0)
>>>> - return ret;
>>>> + if (pm_runtime_enabled(slave->bus->dev)) {
>>>> + ret = pm_runtime_get_sync(slave->bus->dev);
>>>> + if (ret < 0)
>>>> + return ret;
>>>> + }
>>>>
>>>> ret = sdw_transfer(slave->bus, &msg);
>>>> - pm_runtime_put(slave->bus->dev);
>>>> +
>>>> + if (pm_runtime_enabled(slave->bus->dev))
>>>> + pm_runtime_put(slave->bus->dev);
>>>>
>>>> return ret;
>>>> }
>>>> @@ -359,13 +363,16 @@ int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
>>>> slave->dev_num, SDW_MSG_FLAG_WRITE, val);
>>>> if (ret < 0)
>>>> return ret;
>>>> -
>>>> - ret = pm_runtime_get_sync(slave->bus->dev);
>>>> - if (ret < 0)
>>>> - return ret;
>>>> + if (pm_runtime_enabled(slave->bus->dev)) {
>>>> + ret = pm_runtime_get_sync(slave->bus->dev);
>>>> + if (ret < 0)
>>>> + return ret;
>>>> + }
>>>>
>>>> ret = sdw_transfer(slave->bus, &msg);
>>>> - pm_runtime_put(slave->bus->dev);
>>>> +
>>>> + if (pm_runtime_enabled(slave->bus->dev))
>>>> + pm_runtime_put(slave->bus->dev);
>>>>
>>>> return ret;
>>>> }
>>>> --
>>>> 2.20.1
>>>>
>>>> _______________________________________________
>>>> Alsa-devel mailing list
>>>> [email protected]
>>>> https://urldefense.proofpoint.com/v2/url?u=https-3A__mailman.alsa-2Dproject.org_mailman_listinfo_alsa-2Ddevel&d=DwIBAg&c=aUq983L2pue2FqKFoP6PGHMJQyoJ7kl3s3GZ-_haXqY&r=g7GAQENVXx_RQdyXHInPMg&m=vETGQLSPeGb7K_ZsXv4Tl3VFfdXzyummTDga97ozJcg&s=LiW4SToh5U0zhnkox54oRhJ1u3vFNbBB9nmzRDuCDjI&e=
>>
>> _______________________________________________
>> Alsa-devel mailing list
>> [email protected]
>> https://urldefense.proofpoint.com/v2/url?u=https-3A__mailman.alsa-2Dproject.org_mailman_listinfo_alsa-2Ddevel&d=DwIBAg&c=aUq983L2pue2FqKFoP6PGHMJQyoJ7kl3s3GZ-_haXqY&r=g7GAQENVXx_RQdyXHInPMg&m=i_0S359hFIVqNgv3fR5_MNzDOHP99trdXszZ-FMiQEE&s=RxPHxKfI3v6Fkh7qzKjq8sNi-5QMoY8XfyMDSquA38o&e=

2019-07-26 08:44:22

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled

On Fri, Jul 26, 2019 at 08:33:35AM +0000, Jan Kotas wrote:
>
>
> > On 26 Jul 2019, at 10:22, Guennadi Liakhovetski <[email protected]> wrote:
> >
> > EXTERNAL MAIL
> >
> >
> > Hi Jan,
> >
> > On Fri, Jul 26, 2019 at 07:47:04AM +0000, Jan Kotas wrote:
> >> Hello,
> >>
> >> I while back I proposed a patch for this, but it went nowhere.
> >>
> >> https://urldefense.proofpoint.com/v2/url?u=https-3A__patchwork.kernel.org_patch_10887405_&d=DwIBAg&c=aUq983L2pue2FqKFoP6PGHMJQyoJ7kl3s3GZ-_haXqY&r=g7GAQENVXx_RQdyXHInPMg&m=i_0S359hFIVqNgv3fR5_MNzDOHP99trdXszZ-FMiQEE&s=ddktFZYlePh-bC7kXeoKWt4QomupzHATK4FLY4oSWKA&e=
> >> Maybe something similar can be implemented?
> >
> > Yes, I was thinking about checkint -EACCESS too, but then I noticed this code
> > in rpm_resume():
> >
> > else if (dev->power.disable_depth == 1 && dev->power.is_suspended
> > && dev->power.runtime_status == RPM_ACTIVE)
> > retval = 1;
> >
> > i.e. if RT-PM is disabled on the device (but only exactly once?..) and it's
> > active and the device is suspended for a system suspend, the function will
> > return 1. I don't understand the logic of this code, but it seems to me it
> > could break the -EACCESS check?
> >
>
> Hi,
>
> In such case ret < 0 will not be true, which I think is fine,
> if I’m understanding you correctly.

Yes, if we just have to distinguish a single case "RT-PM is enabled and it failed."
Which is indeed the case here, it seems. However if we want to check whether RT-PM
is disabled after a call to, say, pm_runtime_get_sync(), then just checking
-EACCESS isn't always enough - there can be cases when RT-PM is disabled and the
return code is 1. But yes, just for checking for failures, like here, it should be
fine.

Thanks
Guennadi

> >> Jan
> >>
> >>> On 26 Jul 2019, at 09:39, Guennadi Liakhovetski <[email protected]> wrote:
> >>>
> >>> EXTERNAL MAIL
> >>>
> >>>
> >>> Hi Pierre,
> >>>
> >>> I might be wrong but this doesn't seem right to me. (Supposedly) all RT-PM
> >>> functions check for "enabled" internally. The only thing that can happen is
> >>> that if RT-PM isn't enabled some of those functions will return an error.
> >>> So, in those cases where the return value of RT-PM functions isn't checked,
> >>> I don't think you need to do anything. Where it is checked maybe do
> >>>
> >>> + if (ret < 0 && pm_runtime_enabled(slave->bus->dev))
> >>>
> >>> Thanks
> >>> Guennadi
> >>>
> >>> On Thu, Jul 25, 2019 at 06:40:09PM -0500, Pierre-Louis Bossart wrote:
> >>>> Not all platforms support runtime_pm for now, let's use runtime_pm
> >>>> only when enabled.
> >>>>
> >>>> Suggested-by: Srinivas Kandagatla <[email protected]>
> >>>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> >>>> ---
> >>>> drivers/soundwire/bus.c | 25 ++++++++++++++++---------
> >>>> 1 file changed, 16 insertions(+), 9 deletions(-)
> >>>>
> >>>> diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
> >>>> index 5ad4109dc72f..0a45dc5713df 100644
> >>>> --- a/drivers/soundwire/bus.c
> >>>> +++ b/drivers/soundwire/bus.c
> >>>> @@ -332,12 +332,16 @@ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
> >>>> if (ret < 0)
> >>>> return ret;
> >>>>
> >>>> - ret = pm_runtime_get_sync(slave->bus->dev);
> >>>> - if (ret < 0)
> >>>> - return ret;
> >>>> + if (pm_runtime_enabled(slave->bus->dev)) {
> >>>> + ret = pm_runtime_get_sync(slave->bus->dev);
> >>>> + if (ret < 0)
> >>>> + return ret;
> >>>> + }
> >>>>
> >>>> ret = sdw_transfer(slave->bus, &msg);
> >>>> - pm_runtime_put(slave->bus->dev);
> >>>> +
> >>>> + if (pm_runtime_enabled(slave->bus->dev))
> >>>> + pm_runtime_put(slave->bus->dev);
> >>>>
> >>>> return ret;
> >>>> }
> >>>> @@ -359,13 +363,16 @@ int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
> >>>> slave->dev_num, SDW_MSG_FLAG_WRITE, val);
> >>>> if (ret < 0)
> >>>> return ret;
> >>>> -
> >>>> - ret = pm_runtime_get_sync(slave->bus->dev);
> >>>> - if (ret < 0)
> >>>> - return ret;
> >>>> + if (pm_runtime_enabled(slave->bus->dev)) {
> >>>> + ret = pm_runtime_get_sync(slave->bus->dev);
> >>>> + if (ret < 0)
> >>>> + return ret;
> >>>> + }
> >>>>
> >>>> ret = sdw_transfer(slave->bus, &msg);
> >>>> - pm_runtime_put(slave->bus->dev);
> >>>> +
> >>>> + if (pm_runtime_enabled(slave->bus->dev))
> >>>> + pm_runtime_put(slave->bus->dev);
> >>>>
> >>>> return ret;
> >>>> }
> >>>> --
> >>>> 2.20.1
> >>>>
> >>>> _______________________________________________
> >>>> Alsa-devel mailing list
> >>>> [email protected]
> >>>> https://urldefense.proofpoint.com/v2/url?u=https-3A__mailman.alsa-2Dproject.org_mailman_listinfo_alsa-2Ddevel&d=DwIBAg&c=aUq983L2pue2FqKFoP6PGHMJQyoJ7kl3s3GZ-_haXqY&r=g7GAQENVXx_RQdyXHInPMg&m=vETGQLSPeGb7K_ZsXv4Tl3VFfdXzyummTDga97ozJcg&s=LiW4SToh5U0zhnkox54oRhJ1u3vFNbBB9nmzRDuCDjI&e=
> >>
> >> _______________________________________________
> >> Alsa-devel mailing list
> >> [email protected]
> >> https://urldefense.proofpoint.com/v2/url?u=https-3A__mailman.alsa-2Dproject.org_mailman_listinfo_alsa-2Ddevel&d=DwIBAg&c=aUq983L2pue2FqKFoP6PGHMJQyoJ7kl3s3GZ-_haXqY&r=g7GAQENVXx_RQdyXHInPMg&m=i_0S359hFIVqNgv3fR5_MNzDOHP99trdXszZ-FMiQEE&s=RxPHxKfI3v6Fkh7qzKjq8sNi-5QMoY8XfyMDSquA38o&e=
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 09:24:59

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 01/40] soundwire: add debugfs support

On 2019-07-26 01:39, Pierre-Louis Bossart wrote:
> +static ssize_t sdw_slave_reg_read(struct file *file, char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + struct sdw_slave *slave = file->private_data;
> + unsigned int reg;
> + char *buf;
> + ssize_t ret;
> + int i, j;
> +
> + buf = kzalloc(RD_BUF, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + ret = scnprintf(buf, RD_BUF, "Register Value\n");
> + ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP0\n");
> +
> + for (i = 0; i < 6; i++)
> + ret += sdw_sprintf(slave, buf, ret, i);

In most cases explicit reg macro is used, here it's implicit. Align with
the rest?

> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
> + ret += sdw_sprintf(slave, buf, ret, SDW_DP0_CHANNELEN);
> + for (i = SDW_DP0_SAMPLECTRL1; i <= SDW_DP0_LANECTRL; i++)
> + ret += sdw_sprintf(slave, buf, ret, i);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
> + ret += sdw_sprintf(slave, buf, ret,
> + SDW_DP0_CHANNELEN + SDW_BANK1_OFFSET);
> + for (i = SDW_DP0_SAMPLECTRL1 + SDW_BANK1_OFFSET;
> + i <= SDW_DP0_LANECTRL + SDW_BANK1_OFFSET; i++)
> + ret += sdw_sprintf(slave, buf, ret, i);

I'd advice to revisit macros declarations first.
There should be SDW_DP0_SAMPLECTRL1_B(bank) declared. In general all
macros for SDW should be "bank-less" (name wise). Additionally,
SDW_BANK_OFFSET(bank) could be provided for convenience i.e.: return 0
for bank0.
Yeah, there might be some speed loss in terms of operation count but in
most cases it is negligible.

Would simplify this entire reg dump greatly.
const array on top with {0, 1} elements and replacing explicit "bank0/1"
strings with "bank%d" gets code size reduced while not losing on
readability.

> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "\nSCP\n");
> + for (i = SDW_SCP_INT1; i <= SDW_SCP_BANKDELAY; i++)
> + ret += sdw_sprintf(slave, buf, ret, i);
> + for (i = SDW_SCP_DEVID_0; i <= SDW_SCP_DEVID_5; i++)
> + ret += sdw_sprintf(slave, buf, ret, i);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
> + ret += sdw_sprintf(slave, buf, ret, SDW_SCP_FRAMECTRL_B0);
> + ret += sdw_sprintf(slave, buf, ret, SDW_SCP_NEXTFRAME_B0);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
> + ret += sdw_sprintf(slave, buf, ret, SDW_SCP_FRAMECTRL_B1);
> + ret += sdw_sprintf(slave, buf, ret, SDW_SCP_NEXTFRAME_B1);
> +
> + for (i = 1; i < 14; i++) {

Explicit valid slave addresses would be preferred.

> + ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP%d\n", i);
> + reg = SDW_DPN_INT(i);
> + for (j = 0; j < 6; j++)
> + ret += sdw_sprintf(slave, buf, ret, reg + j);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
> + reg = SDW_DPN_CHANNELEN_B0(i);
> + for (j = 0; j < 9; j++)
> + ret += sdw_sprintf(slave, buf, ret, reg + j);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
> + reg = SDW_DPN_CHANNELEN_B1(i);
> + for (j = 0; j < 9; j++)
> + ret += sdw_sprintf(slave, buf, ret, reg + j);

Some sort of MAX_CHANNELS would be nice here too.

> + }
> +
> + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> + kfree(buf);
> +
> + return ret;
> +}
> +
> +static const struct file_operations sdw_slave_reg_fops = {
> + .open = simple_open,
> + .read = sdw_slave_reg_read,
> + .llseek = default_llseek,
> +};
> +
> +struct dentry *sdw_slave_debugfs_init(struct sdw_slave *slave)
> +{
> + struct dentry *master;
> + struct dentry *d;
> + char name[32];
> +
> + master = slave->bus->debugfs;
> +
> + /* create the debugfs slave-name */
> + snprintf(name, sizeof(name), "%s", dev_name(&slave->dev));
> + d = debugfs_create_dir(name, master);
> +
> + debugfs_create_file("registers", 0400, d, slave, &sdw_slave_reg_fops);

Pointer returned by _create_file gets completely ignored here. At least
dbg msg would be nice if it fails.

> + return d;
> +}
> +

2019-07-26 09:37:00

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 04/40] soundwire: intel: add debugfs register dump

On 2019-07-26 01:39, Pierre-Louis Bossart wrote:
> +static void intel_debugfs_init(struct sdw_intel *sdw)
> +{
> + struct dentry *root = sdw->cdns.bus.debugfs;
> +
> + if (!root)
> + return;
> +
> + sdw->fs = debugfs_create_dir("intel-sdw", root);
> + if (IS_ERR_OR_NULL(sdw->fs)) {
> + dev_err(sdw->cdns.dev, "debugfs root creation failed\n");
> + sdw->fs = NULL;
> + return;
> + }
> +
> + debugfs_create_file("intel-registers", 0400, sdw->fs, sdw,
> + &intel_reg_fops);
> +
> + sdw_cdns_debugfs_init(&sdw->cdns, sdw->fs);
> +}

I believe there should be dummy equivalent of _init and _exit if debugfs
is not enabled (if these are defined already and I've missed it, please
ignore).

> +static void intel_debugfs_exit(struct sdw_intel *sdw)
> +{
> + debugfs_remove_recursive(sdw->fs);
> +}

2019-07-26 09:40:15

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 03/40] soundwire: cadence_master: align debugfs to 8 digits

On 2019-07-26 01:39, Pierre-Louis Bossart wrote:
> SQUASHME
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 91e8bacb83e3..9f611a1fff0a 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -234,7 +234,7 @@ static ssize_t cdns_sprintf(struct sdw_cdns *cdns,
> char *buf, size_t pos, unsigned int reg)
> {
> return scnprintf(buf + pos, RD_BUF - pos,
> - "%4x\t%4x\n", reg, cdns_readl(cdns, reg));
> + "%4x\t%8x\n", reg, cdns_readl(cdns, reg));
> }
>
> static ssize_t cdns_reg_read(struct file *file, char __user *user_buf,
>

Should just be merged together with the introducing commit. Guess it's
posted unintentionally.

2019-07-26 09:47:19

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 06/40] soundwire: intel: prevent possible dereference in hw_params

On 2019-07-26 01:39, Pierre-Louis Bossart wrote:
> This should not happen in production systems but we should test for
> all callback arguments before invoking the config_stream callback.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/intel.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index 68832e613b1e..497879dd9c0d 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -509,7 +509,7 @@ static int intel_config_stream(struct sdw_intel *sdw,
> struct snd_soc_dai *dai,
> struct snd_pcm_hw_params *hw_params, int link_id)
> {
> - if (sdw->res->ops && sdw->res->ops->config_stream)
> + if (sdw->res->ops && sdw->res->ops->config_stream && sdw->res->arg)
> return sdw->res->ops->config_stream(sdw->res->arg,
> substream, dai, hw_params, link_id);
>
>

Hmm, declaring local for sdw->res should prove useful here after
addition of 4th sdw->res dereference.

2019-07-26 09:55:38

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 09/40] soundwire: cadence_master: fix usage of CONFIG_UPDATE

On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
> /*
> * debugfs
> */
> @@ -758,15 +774,9 @@ static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
> */
> int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
> {
> - int ret;
> -
> _cdns_enable_interrupt(cdns);
> - ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
> - CDNS_MCP_CONFIG_UPDATE_BIT);
> - if (ret < 0)
> - dev_err(cdns->dev, "Config update timedout\n");
>
> - return ret;
> + return 0;
> }
> EXPORT_SYMBOL(sdw_cdns_enable_interrupt);

Rather than ignoring _cdns_enable_interrupt - despite said func always
returning 0 - simply do: return _cnds_enable_interrupt(cdns) and flag
caller with inline.

Afterwards, one can think if such encapsulation is even required -
remove existing sdw_cdns_enable_interrupt and rename _cnds_enable_interrupt?

2019-07-26 09:55:57

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 09/40] soundwire: cadence_master: fix usage of CONFIG_UPDATE



On 2019-07-26 11:53, Cezary Rojewski wrote:
> On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
>>   /*
>>    * debugfs
>>    */
>> @@ -758,15 +774,9 @@ static int _cdns_enable_interrupt(struct sdw_cdns
>> *cdns)
>>    */
>>   int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
>>   {
>> -    int ret;
>> -
>>       _cdns_enable_interrupt(cdns);
>> -    ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
>> -                 CDNS_MCP_CONFIG_UPDATE_BIT);
>> -    if (ret < 0)
>> -        dev_err(cdns->dev, "Config update timedout\n");
>> -    return ret;
>> +    return 0;
>>   }
>>   EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
>
> Rather than ignoring _cdns_enable_interrupt - despite said func always
> returning 0 - simply do: return _cnds_enable_interrupt(cdns) and flag
> caller with inline.
>
> Afterwards, one can think if such encapsulation is even required -
> remove existing sdw_cdns_enable_interrupt and rename
> _cnds_enable_interrupt?

Nevermind, I see you simplified it in the next patch..

2019-07-26 10:05:45

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 20/40] soundwire: prototypes for suspend/resume

On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.h | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
> index c0bf6ff00a44..d375bbfead18 100644
> --- a/drivers/soundwire/cadence_master.h
> +++ b/drivers/soundwire/cadence_master.h
> @@ -165,6 +165,9 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
>
> void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
>
> +int sdw_cdns_suspend(struct sdw_cdns *cdns);
> +bool sdw_cdns_check_resume_status(struct sdw_cdns *cdns);
> +
> int sdw_cdns_get_stream(struct sdw_cdns *cdns,
> struct sdw_cdns_streams *stream,
> u32 ch, u32 dir);
>

No commit message, guess it's SQUASHME commit and shouldn't be part of
overall series.

2019-07-26 10:31:56

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 29/40] soundwire: intel_init: add kernel module parameter to filter out links

On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
> @@ -83,6 +87,9 @@ static struct sdw_intel_ctx
> caps = ioread32(res->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
> caps &= GENMASK(2, 0);
>
> + dev_dbg(&adev->dev, "SoundWire links: BIOS count %d hardware caps %d\n",
> + count, caps);
> +
> /* Check HW supported vs property value and use min of two */
> count = min_t(u8, caps, count);
>

This message does not look like it belongs to current patch - no
link_mask dependency whatsoever. There have been couple "informative"
patches in your series, maybe schedule it with them instead (as a
separate series)?


2019-07-26 10:40:54

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 31/40] soundwire: intel: move shutdown() callback and don't export symbol

On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
> +void intel_shutdown(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct sdw_cdns_dma_data *dma;
> +
> + dma = snd_soc_dai_get_dma_data(dai, substream);
> + if (!dma)
> + return;
> +
> + snd_soc_dai_set_dma_data(dai, substream, NULL);
> + kfree(dma);
> +}

Correct me if I'm wrong, but do we really need to _get_dma_ here?
_set_dma_ seems bulletproof, same for kfree.

2019-07-26 10:45:40

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 32/40] soundwire: intel: add helper for initialization

On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
> Move code to helper for reuse in power management routines
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/intel.c | 16 +++++++++++-----
> 1 file changed, 11 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index c40ab443e723..215dc81cdf73 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -984,6 +984,15 @@ static struct sdw_master_ops sdw_intel_ops = {
> .post_bank_switch = intel_post_bank_switch,
> };
>
> +static int intel_init(struct sdw_intel *sdw)
> +{
> + /* Initialize shim and controller */
> + intel_link_power_up(sdw);
> + intel_shim_init(sdw);
> +
> + return sdw_cdns_init(&sdw->cdns);
> +}

Why don't we check polling status for _link_power_up? I've already met
slow starting devices in the past. If polling fails and -EAGAIN is
returned, flow of initialization should react appropriately e.g. poll
till MAX_TIMEOUT of some sort -or- collapse.

2019-07-26 10:52:59

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 33/40] soundwire: intel: Add basic power management support

On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
> +static int intel_resume(struct device *dev)
> +{
> + struct sdw_intel *sdw;
> + int ret;
> +
> + sdw = dev_get_drvdata(dev);
> +
> + ret = intel_init(sdw);
> + if (ret) {
> + dev_err(dev, "%s failed: %d", __func__, ret);
> + return ret;
> + }
> +
> + sdw_cdns_enable_interrupt(&sdw->cdns);
> +
> + return ret;
> +}
> +
> +#endif

Suggestion: the local declaration + initialization via dev_get_drvdata()
are usually combined.

Given the upstream declaration of _enable_interrupt, it does return
error code/ success. Given current flow, if function gets to
_enable_interrupt call, ret is already set to 0. Returning
sdw_cds_enable_interrupt() directly would both simplify the definition
and prevent status loss.

2019-07-26 10:55:42

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 23/40] soundwire: stream: fix disable sequence

On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
>
> - return do_bank_switch(stream);
> + ret = do_bank_switch(stream);
> + if (ret < 0) {
> + dev_err(bus->dev, "Bank switch failed: %d\n", ret);
> + return ret;
> + }
> +
> + /* make sure alternate bank (previous current) is also disabled */
> + list_for_each_entry(m_rt, &stream->master_list, stream_node) {
> + bus = m_rt->bus;
> + /* Disable port(s) */
> + ret = sdw_enable_disable_ports(m_rt, false);
> + if (ret < 0) {
> + dev_err(bus->dev, "Disable port(s) failed: %d\n", ret);
> + return ret;
> + }
> + }
> +
> + return 0;
> }
>
> /**
>

While not directly connected to this commit, I see that you do:
link_for_each_entry(m_rt, &stream->master_list, stream_node)

quite often in /stream.c code. Helpful macro would prove useful.

2019-07-26 11:11:29

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 27/40] soundwire: Add Intel resource management algorithm

On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
> This algorithm computes bus parameters like clock frequency, frame
> shape and port transport parameters based on active stream(s) running
> on the bus.
>
> This implementation is optimal for Intel platforms. Developers can
> also implement their own .compute_params() callback for specific
> resource management algorithm.
>
> Credits: this patch is based on an earlier internal contribution by
> Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. All hard-coded
> values were removed from the initial contribution to use BIOS
> information instead.
>
> FIXME: remove checkpatch report
> WARNING: Reusing the krealloc arg is almost always a bug
> + group->rates = krealloc(group->rates,
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>

Could you specify the requirements and limitations for this algorithm?
Last year I written calc for Linux based on Windows (please don't burn
me here) equivalent though said requirements/ limitiations might have
changed and nothing is valid any longer.

I remember that some parts of specification overcomplicated the
calculator and due to actual, realtime usecases it could be greatly
simplified (that's why I mention that my work is probably no longer
valid). However, these details would help me in reviewing your
implementation and providing suggestions.

And yes, "Frame shape calculator" probably suits this better.
Though this might be just a preference thingy : )

2019-07-26 11:23:59

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 24/40] soundwire: cadence_master: use BIOS defaults for frame shape

On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
> +static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
> +{
> + u32 val;
> + int c;
> + int r;
> +
> + r = sdw_find_row_index(n_rows);
> + c = sdw_find_col_index(n_cols);
> +
> + val = (r << 3) | c;
> +
> + return val;
> +}
> +
> /**
> * sdw_cdns_init() - Cadence initialization
> * @cdns: Cadence instance
> @@ -977,7 +990,9 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
> cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
>
> /* Set the default frame shape */
> - cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT, CDNS_DEFAULT_FRAME_SHAPE);
> + val = cdns_set_default_frame_shape(prop->default_row,
> + prop->default_col);
> + cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT, val);
>
> /* Set SSP interval to default value */
> cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, CDNS_DEFAULT_SSP_INTERVAL);
>

Suggestion:
declare "generic" _get_frame_frame(rows, cols) instead and let it do the
bitwise operations for you. Pretty sure this won't be the only place in
code where reg value for frame_shape needs to be prepared.

Said function could be as simple as:
return (row << 3) | cols;
+inline flag

i.e. could be even a macro..

Otherwise modify _set_default_frame_shape to simply:
return (r << 3) | c

without involving additional local val variable (I don't really see the
point for any locals there though).

2019-07-26 11:29:45

by Cezary Rojewski

[permalink] [raw]
Subject: Re: [RFC PATCH 00/40] soundwire: updates for 5.4

On 2019-07-26 01:39, Pierre-Louis Bossart wrote:
> The existing upstream code allows for SoundWire devices to be
> enumerated and managed by the bus, but streaming is not currently
> supported.
>
> Bard Liao, Rander Wang and I did quite a bit of integration/validation
> work to close this gap and we now have SoundWire streaming + basic
> power managemement on Intel CometLake and IceLake reference
> boards. These changes are still preliminary and should not be merged
> as is, but it's time to start reviews. While the number of patches is
> quite large, each of the changes is quite small.
>
> SOF driver changes will be submitted shortly as well but are still
> being validated.
>
> ClockStop modes and synchronized playback on
> multiple links are not supported for now and will likely be part of
> the next cycle (dependencies on codec drivers and multi-cpu DAI
> support).
>
> Acknowledgements: This work would not have been possible without the
> support of Slawomir Blauciak and Tomasz Lauda on the SOF side,
> currently being reviewed, see
> https://github.com/thesofproject/sof/pull/1638
>
> Comments and feedback welcome!

Hello Pierre,

This patchset is pretty large - I'd suggest dividing next RFC into
segments: debugfs, info, power-management, basic flow corrections and
frame shape calculator.
Some commits have no messages and others lack additional info - tried to
provide feedback wherever I could, though, especially for the last one,
it would be vital to post additional info so in-depth feedback can be
provided.

Maybe nothing for calculator will come up, maybe something will. In
general I remember it being an essential part of SDW and one where many
bugs where found during the initial verification phase.

Thanks for your contribution and have a good day!
Czarek

2019-07-26 14:00:10

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 03/40] soundwire: cadence_master: align debugfs to 8 digits



On 7/26/19 4:38 AM, Cezary Rojewski wrote:
> On 2019-07-26 01:39, Pierre-Louis Bossart wrote:
>> SQUASHME
>>
>> Signed-off-by: Pierre-Louis Bossart
>> <[email protected]>
>> ---
>>   drivers/soundwire/cadence_master.c | 2 +-
>>   1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/soundwire/cadence_master.c
>> b/drivers/soundwire/cadence_master.c
>> index 91e8bacb83e3..9f611a1fff0a 100644
>> --- a/drivers/soundwire/cadence_master.c
>> +++ b/drivers/soundwire/cadence_master.c
>> @@ -234,7 +234,7 @@ static ssize_t cdns_sprintf(struct sdw_cdns *cdns,
>>                   char *buf, size_t pos, unsigned int reg)
>>   {
>>       return scnprintf(buf + pos, RD_BUF - pos,
>> -             "%4x\t%4x\n", reg, cdns_readl(cdns, reg));
>> +             "%4x\t%8x\n", reg, cdns_readl(cdns, reg));
>>   }
>>   static ssize_t cdns_reg_read(struct file *file, char __user *user_buf,
>>
>
> Should just be merged together with the introducing commit. Guess it's
> posted unintentionally.

Yep, I missed this, will squash in the updates as intended.

2019-07-26 14:00:26

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 01/40] soundwire: add debugfs support

Thanks for the feedback Cezary.

>> +static ssize_t sdw_slave_reg_read(struct file *file, char __user
>> *user_buf,
>> +                  size_t count, loff_t *ppos)
>> +{
>> +    struct sdw_slave *slave = file->private_data;
>> +    unsigned int reg;
>> +    char *buf;
>> +    ssize_t ret;
>> +    int i, j;
>> +
>> +    buf = kzalloc(RD_BUF, GFP_KERNEL);
>> +    if (!buf)
>> +        return -ENOMEM;
>> +
>> +    ret = scnprintf(buf, RD_BUF, "Register  Value\n");
>> +    ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP0\n");
>> +
>> +    for (i = 0; i < 6; i++)
>> +        ret += sdw_sprintf(slave, buf, ret, i);
>
> In most cases explicit reg macro is used, here it's implicit. Align with
> the rest?

I don't see what you are referring to, or I need more coffee.
we use this function sdw_printf in a number of places. Or are you
referring to the magic value 6? That should indeed be a macro.

>> +
>> +    ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
>> +    ret += sdw_sprintf(slave, buf, ret, SDW_DP0_CHANNELEN);
>> +    for (i = SDW_DP0_SAMPLECTRL1; i <= SDW_DP0_LANECTRL; i++)
>> +        ret += sdw_sprintf(slave, buf, ret, i);
>> +
>> +    ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
>> +    ret += sdw_sprintf(slave, buf, ret,
>> +            SDW_DP0_CHANNELEN + SDW_BANK1_OFFSET);
>> +    for (i = SDW_DP0_SAMPLECTRL1 + SDW_BANK1_OFFSET;
>> +            i <= SDW_DP0_LANECTRL + SDW_BANK1_OFFSET; i++)
>> +        ret += sdw_sprintf(slave, buf, ret, i);
>
> I'd advice to revisit macros declarations first.
> There should be SDW_DP0_SAMPLECTRL1_B(bank) declared. In general all
> macros for SDW should be "bank-less" (name wise). Additionally,
> SDW_BANK_OFFSET(bank) could be provided for convenience i.e.: return 0
> for bank0.
> Yeah, there might be some speed loss in terms of operation count but in
> most cases it is negligible.
>
> Would simplify this entire reg dump greatly.
> const array on top with {0, 1} elements and replacing explicit "bank0/1"
> strings with "bank%d" gets code size reduced while not losing on
> readability.

This could require a lot of changes in other parts of the code, and I
don't want to do this just for debugfs. It's valid point that maybe the
code can be simplified, but the changes are an across-the-board change
to be done when we don't add new functionality. I'll keep this on the
todo list.

>
>> +
>> +    ret += scnprintf(buf + ret, RD_BUF - ret, "\nSCP\n");
>> +    for (i = SDW_SCP_INT1; i <= SDW_SCP_BANKDELAY; i++)
>> +        ret += sdw_sprintf(slave, buf, ret, i);
>> +    for (i = SDW_SCP_DEVID_0; i <= SDW_SCP_DEVID_5; i++)
>> +        ret += sdw_sprintf(slave, buf, ret, i);
>> +
>> +    ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
>> +    ret += sdw_sprintf(slave, buf, ret, SDW_SCP_FRAMECTRL_B0);
>> +    ret += sdw_sprintf(slave, buf, ret, SDW_SCP_NEXTFRAME_B0);
>> +
>> +    ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
>> +    ret += sdw_sprintf(slave, buf, ret, SDW_SCP_FRAMECTRL_B1);
>> +    ret += sdw_sprintf(slave, buf, ret, SDW_SCP_NEXTFRAME_B1);
>> +
>> +    for (i = 1; i < 14; i++) {
>
> Explicit valid slave addresses would be preferred.

no, these are ports. we should use a macro instead of the magic 14 but
it's fine to try and read all ports. As I explained it's a good way to
figure out how many ports the Slave device supports even in the absence
of documentation. This also helps figure out if the DisCo properties
make sense.

>
>> +        ret += scnprintf(buf + ret, RD_BUF - ret, "\nDP%d\n", i);
>> +        reg = SDW_DPN_INT(i);
>> +        for (j = 0; j < 6; j++)
>> +            ret += sdw_sprintf(slave, buf, ret, reg + j);
>> +
>> +        ret += scnprintf(buf + ret, RD_BUF - ret, "Bank0\n");
>> +        reg = SDW_DPN_CHANNELEN_B0(i);
>> +        for (j = 0; j < 9; j++)
>> +            ret += sdw_sprintf(slave, buf, ret, reg + j);
>> +
>> +        ret += scnprintf(buf + ret, RD_BUF - ret, "Bank1\n");
>> +        reg = SDW_DPN_CHANNELEN_B1(i);
>> +        for (j = 0; j < 9; j++)
>> +            ret += sdw_sprintf(slave, buf, ret, reg + j);
>
> Some sort of MAX_CHANNELS would be nice here too.

Yes, need to use macros indeed.

>> +struct dentry *sdw_slave_debugfs_init(struct sdw_slave *slave)
>> +{
>> +    struct dentry *master;
>> +    struct dentry *d;
>> +    char name[32];
>> +
>> +    master = slave->bus->debugfs;
>> +
>> +    /* create the debugfs slave-name */
>> +    snprintf(name, sizeof(name), "%s", dev_name(&slave->dev));
>> +    d = debugfs_create_dir(name, master);
>> +
>> +    debugfs_create_file("registers", 0400, d, slave,
>> &sdw_slave_reg_fops);
>
> Pointer returned by _create_file gets completely ignored here. At least
> dbg msg would be nice if it fails.
>
>> +    return d;

I understood that Greg KH doesn't want us to depend on the result of
debugfs calls, but a dev_dbg is likely ok.

2019-07-26 14:02:35

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 04/40] soundwire: intel: add debugfs register dump



On 7/26/19 4:35 AM, Cezary Rojewski wrote:
> On 2019-07-26 01:39, Pierre-Louis Bossart wrote:
>> +static void intel_debugfs_init(struct sdw_intel *sdw)
>> +{
>> +    struct dentry *root = sdw->cdns.bus.debugfs;
>> +
>> +    if (!root)
>> +        return;
>> +
>> +    sdw->fs = debugfs_create_dir("intel-sdw", root);
>> +    if (IS_ERR_OR_NULL(sdw->fs)) {
>> +        dev_err(sdw->cdns.dev, "debugfs root creation failed\n");
>> +        sdw->fs = NULL;
>> +        return;
>> +    }
>> +
>> +    debugfs_create_file("intel-registers", 0400, sdw->fs, sdw,
>> +                &intel_reg_fops);
>> +
>> +    sdw_cdns_debugfs_init(&sdw->cdns, sdw->fs);
>> +}
>
> I believe there should be dummy equivalent of _init and _exit if debugfs
> is not enabled (if these are defined already and I've missed it, please
> ignore).

I think the direction is just to keep going if there is an error or
debufs is not enabled.

>
>> +static void intel_debugfs_exit(struct sdw_intel *sdw)
>> +{
>> +    debugfs_remove_recursive(sdw->fs);
>> +}

2019-07-26 14:04:49

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 06/40] soundwire: intel: prevent possible dereference in hw_params


>> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
>> index 68832e613b1e..497879dd9c0d 100644
>> --- a/drivers/soundwire/intel.c
>> +++ b/drivers/soundwire/intel.c
>> @@ -509,7 +509,7 @@ static int intel_config_stream(struct sdw_intel *sdw,
>>                      struct snd_soc_dai *dai,
>>                      struct snd_pcm_hw_params *hw_params, int link_id)
>>   {
>> -    if (sdw->res->ops && sdw->res->ops->config_stream)
>> +    if (sdw->res->ops && sdw->res->ops->config_stream && sdw->res->arg)
>>           return sdw->res->ops->config_stream(sdw->res->arg,
>>                   substream, dai, hw_params, link_id);
>>
>
> Hmm, declaring local for sdw->res should prove useful here after
> addition of 4th sdw->res dereference.

yes, it's an eyesore. I added this to quickly fix a kernel oops while
debugging, will simplify. thanks for the note.

2019-07-26 14:05:27

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [RFC PATCH 01/40] soundwire: add debugfs support

On Thu, Jul 25, 2019 at 06:39:53PM -0500, Pierre-Louis Bossart wrote:
> Add base debugfs mechanism for SoundWire bus by creating soundwire
> root and master-N and slave-x hierarchy.
>
> Also add SDW Slave SCP, DP0 and DP-N register debug file.
>
> Registers not implemented will print as "XX"
>
> Credits: this patch is based on an earlier internal contribution by
> Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. The main change
> is the use of scnprintf to avoid known issues with snprintf.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/Makefile | 4 +-
> drivers/soundwire/bus.c | 6 ++
> drivers/soundwire/bus.h | 24 ++++++
> drivers/soundwire/bus_type.c | 3 +
> drivers/soundwire/debugfs.c | 156 ++++++++++++++++++++++++++++++++++
> drivers/soundwire/slave.c | 1 +
> include/linux/soundwire/sdw.h | 4 +
> 7 files changed, 197 insertions(+), 1 deletion(-)
> create mode 100644 drivers/soundwire/debugfs.c
>
> diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile
> index fd99a831b92a..88990cac48a7 100644
> --- a/drivers/soundwire/Makefile
> +++ b/drivers/soundwire/Makefile
> @@ -4,7 +4,9 @@
> #
>
> #Bus Objs
> -soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o
> +soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o \
> + debugfs.o
> +
> obj-$(CONFIG_SOUNDWIRE_BUS) += soundwire-bus.o
>
> #Cadence Objs
> diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
> index fe745830a261..5ad4109dc72f 100644
> --- a/drivers/soundwire/bus.c
> +++ b/drivers/soundwire/bus.c
> @@ -49,6 +49,8 @@ int sdw_add_bus_master(struct sdw_bus *bus)
> }
> }
>
> + bus->debugfs = sdw_bus_debugfs_init(bus);
> +
> /*
> * Device numbers in SoundWire are 0 through 15. Enumeration device
> * number (0), Broadcast device number (15), Group numbers (12 and
> @@ -109,6 +111,8 @@ static int sdw_delete_slave(struct device *dev, void *data)
> struct sdw_slave *slave = dev_to_sdw_dev(dev);
> struct sdw_bus *bus = slave->bus;
>
> + sdw_slave_debugfs_exit(slave->debugfs);
> +
> mutex_lock(&bus->bus_lock);
>
> if (slave->dev_num) /* clear dev_num if assigned */
> @@ -130,6 +134,8 @@ static int sdw_delete_slave(struct device *dev, void *data)
> void sdw_delete_bus_master(struct sdw_bus *bus)
> {
> device_for_each_child(bus->dev, NULL, sdw_delete_slave);
> +
> + sdw_bus_debugfs_exit(bus->debugfs);
> }
> EXPORT_SYMBOL(sdw_delete_bus_master);
>
> diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
> index 3048ca153f22..06ac4adb0074 100644
> --- a/drivers/soundwire/bus.h
> +++ b/drivers/soundwire/bus.h
> @@ -18,6 +18,30 @@ static inline int sdw_acpi_find_slaves(struct sdw_bus *bus)
> void sdw_extract_slave_id(struct sdw_bus *bus,
> u64 addr, struct sdw_slave_id *id);
>
> +#ifdef CONFIG_DEBUG_FS
> +struct dentry *sdw_bus_debugfs_init(struct sdw_bus *bus);
> +void sdw_bus_debugfs_exit(struct dentry *d);
> +struct dentry *sdw_slave_debugfs_init(struct sdw_slave *slave);
> +void sdw_slave_debugfs_exit(struct dentry *d);
> +void sdw_debugfs_init(void);
> +void sdw_debugfs_exit(void);
> +#else
> +struct dentry *sdw_bus_debugfs_init(struct sdw_bus *bus)
> +{ return NULL; }
> +
> +void sdw_bus_debugfs_exit(struct dentry *d) {}
> +
> +struct dentry *sdw_slave_debugfs_init(struct sdw_slave *slave)
> +{ return NULL; }
> +
> +void sdw_slave_debugfs_exit(struct dentry *d) {}
> +
> +void sdw_debugfs_init(void) {}
> +
> +void sdw_debugfs_exit(void) {}
> +
> +#endif
> +
> enum {
> SDW_MSG_FLAG_READ = 0,
> SDW_MSG_FLAG_WRITE,
> diff --git a/drivers/soundwire/bus_type.c b/drivers/soundwire/bus_type.c
> index 2655602f0cfb..4a465f55039f 100644
> --- a/drivers/soundwire/bus_type.c
> +++ b/drivers/soundwire/bus_type.c
> @@ -6,6 +6,7 @@
> #include <linux/pm_domain.h>
> #include <linux/soundwire/sdw.h>
> #include <linux/soundwire/sdw_type.h>
> +#include "bus.h"
>
> /**
> * sdw_get_device_id - find the matching SoundWire device id
> @@ -177,11 +178,13 @@ EXPORT_SYMBOL_GPL(sdw_unregister_driver);
>
> static int __init sdw_bus_init(void)
> {
> + sdw_debugfs_init();
> return bus_register(&sdw_bus_type);
> }
>
> static void __exit sdw_bus_exit(void)
> {
> + sdw_debugfs_exit();
> bus_unregister(&sdw_bus_type);
> }
>
> diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c
> new file mode 100644
> index 000000000000..8d86e100516e
> --- /dev/null
> +++ b/drivers/soundwire/debugfs.c
> @@ -0,0 +1,156 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)

No, for debugfs-specific code, that dual license makes no sense, right?
Don't cargo-cult SPDX identifiers please.

> +// Copyright(c) 2017-19 Intel Corporation.

Spell the year out fully unless you want lawyers knocking on your door :)

> +
> +#include <linux/device.h>
> +#include <linux/debugfs.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/slab.h>
> +#include <linux/soundwire/sdw.h>
> +#include <linux/soundwire/sdw_registers.h>
> +#include "bus.h"
> +
> +#ifdef CONFIG_DEBUG_FS
> +struct dentry *sdw_debugfs_root;
> +#endif

This whole file is not built if that option is not enabled, so why the
#ifdef?

thanks,

greg k-h

2019-07-26 14:06:23

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 09/40] soundwire: cadence_master: fix usage of CONFIG_UPDATE


>> @@ -943,7 +953,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
>>
>> cdns_writel(cdns, CDNS_MCP_CONFIG, val);
>>
>> - return 0;
>> + /* commit changes */
>> + ret = cdns_update_config(cdns);
>> +
>> + return ret;
>
> + return cdns_update_config(cdns);

yes, will fix. thanks!

2019-07-26 14:09:31

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [RFC PATCH 04/40] soundwire: intel: add debugfs register dump

On Thu, Jul 25, 2019 at 06:39:56PM -0500, Pierre-Louis Bossart wrote:
> Add debugfs file to dump the Intel SoundWire registers
>
> Credits: this patch is based on an earlier internal contribution by
> Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. The main change
> is the use of scnprintf to avoid known issues with snprintf.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/intel.c | 115 ++++++++++++++++++++++++++++++++++++++
> 1 file changed, 115 insertions(+)
>
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index 317873bc0555..aeadc341c0a3 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -6,6 +6,7 @@
> */
>
> #include <linux/acpi.h>
> +#include <linux/debugfs.h>
> #include <linux/delay.h>
> #include <linux/module.h>
> #include <linux/interrupt.h>
> @@ -16,6 +17,7 @@
> #include <linux/soundwire/sdw.h>
> #include <linux/soundwire/sdw_intel.h>
> #include "cadence_master.h"
> +#include "bus.h"
> #include "intel.h"
>
> /* Intel SHIM Registers Definition */
> @@ -98,6 +100,7 @@ struct sdw_intel {
> struct sdw_cdns cdns;
> int instance;
> struct sdw_intel_link_res *res;
> + struct dentry *fs;
> };
>
> #define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns)
> @@ -161,6 +164,115 @@ static int intel_set_bit(void __iomem *base, int offset, u32 value, u32 mask)
> return -EAGAIN;
> }
>
> +/*
> + * debugfs
> + */
> +
> +#define RD_BUF (2 * PAGE_SIZE)
> +
> +static ssize_t intel_sprintf(void __iomem *mem, bool l,
> + char *buf, size_t pos, unsigned int reg)
> +{
> + int value;
> +
> + if (l)
> + value = intel_readl(mem, reg);
> + else
> + value = intel_readw(mem, reg);
> +
> + return scnprintf(buf + pos, RD_BUF - pos, "%4x\t%4x\n", reg, value);
> +}
> +
> +static ssize_t intel_reg_read(struct file *file, char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + struct sdw_intel *sdw = file->private_data;
> + void __iomem *s = sdw->res->shim;
> + void __iomem *a = sdw->res->alh;
> + char *buf;
> + ssize_t ret;
> + int i, j;
> + unsigned int links, reg;
> +
> + buf = kzalloc(RD_BUF, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + links = intel_readl(s, SDW_SHIM_LCAP) & GENMASK(2, 0);
> +
> + ret = scnprintf(buf, RD_BUF, "Register Value\n");
> + ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n");
> +
> + for (i = 0; i < 4; i++) {
> + reg = SDW_SHIM_LCAP + i * 4;
> + ret += intel_sprintf(s, true, buf, ret, reg);
> + }
> +
> + for (i = 0; i < links; i++) {
> + ret += scnprintf(buf + ret, RD_BUF - ret, "\nLink%d\n", i);
> + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLSCAP(i));
> + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS0CM(i));
> + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS1CM(i));
> + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS2CM(i));
> + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS3CM(i));
> + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PCMSCAP(i));
> +
> + for (j = 0; j < 8; j++) {
> + ret += intel_sprintf(s, false, buf, ret,
> + SDW_SHIM_PCMSYCHM(i, j));
> + ret += intel_sprintf(s, false, buf, ret,
> + SDW_SHIM_PCMSYCHC(i, j));
> + }
> +
> + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PDMSCAP(i));
> + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i));
> + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i));
> + }
> +
> + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKEEN);
> + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKESTS);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret, "\nALH\n");
> + for (i = 0; i < 8; i++)
> + ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i));
> +
> + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> + kfree(buf);
> +
> + return ret;
> +}
> +
> +static const struct file_operations intel_reg_fops = {
> + .open = simple_open,
> + .read = intel_reg_read,
> + .llseek = default_llseek,
> +};

DEFINE_SIMPLE_ATTRIBUTE()?

> +
> +static void intel_debugfs_init(struct sdw_intel *sdw)
> +{
> + struct dentry *root = sdw->cdns.bus.debugfs;
> +
> + if (!root)
> + return;
> +
> + sdw->fs = debugfs_create_dir("intel-sdw", root);
> + if (IS_ERR_OR_NULL(sdw->fs)) {
> + dev_err(sdw->cdns.dev, "debugfs root creation failed\n");

No, come on, don't do that. I've been sweeping the kernel tree to
remove this anti-pattern.

The debugfs core will print an error if you got something wrong, just
call the function and move on, you NEVER need to check the return value
of a debugfs call.

thanks,

greg k-h

2019-07-26 14:10:40

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [RFC PATCH 02/40] soundwire: cadence_master: add debugfs register dump

On Thu, Jul 25, 2019 at 06:39:54PM -0500, Pierre-Louis Bossart wrote:
> Add debugfs file to dump the Cadence master registers
>
> Credits: this patch is based on an earlier internal contribution by
> Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. The main change
> is the use of scnprintf to avoid known issues with snprintf.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 98 ++++++++++++++++++++++++++++++
> drivers/soundwire/cadence_master.h | 2 +
> 2 files changed, 100 insertions(+)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index ff4badc9b3de..91e8bacb83e3 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -8,6 +8,7 @@
>
> #include <linux/delay.h>
> #include <linux/device.h>
> +#include <linux/debugfs.h>
> #include <linux/interrupt.h>
> #include <linux/io.h>
> #include <linux/module.h>
> @@ -223,6 +224,103 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value)
> return -EAGAIN;
> }
>
> +/*
> + * debugfs
> + */
> +
> +#define RD_BUF (2 * PAGE_SIZE)
> +
> +static ssize_t cdns_sprintf(struct sdw_cdns *cdns,
> + char *buf, size_t pos, unsigned int reg)
> +{
> + return scnprintf(buf + pos, RD_BUF - pos,
> + "%4x\t%4x\n", reg, cdns_readl(cdns, reg));
> +}
> +
> +static ssize_t cdns_reg_read(struct file *file, char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + struct sdw_cdns *cdns = file->private_data;
> + char *buf;
> + ssize_t ret;
> + int i, j;
> +
> + buf = kzalloc(RD_BUF, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + ret = scnprintf(buf, RD_BUF, "Register Value\n");
> + ret += scnprintf(buf + ret, RD_BUF - ret, "\nMCP Registers\n");
> + for (i = 0; i < 8; i++) /* 8 MCP registers */
> + ret += cdns_sprintf(cdns, buf, ret, i * 4);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nStatus & Intr Registers\n");
> + for (i = 0; i < 13; i++) /* 13 Status & Intr registers */
> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_STAT + i * 4);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nSSP & Clk ctrl Registers\n");
> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL0);
> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL1);
> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL0);
> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL1);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nDPn B0 Registers\n");
> + for (i = 0; i < 7; i++) {
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nDP-%d\n", i);
> + for (j = 0; j < 6; j++)
> + ret += cdns_sprintf(cdns, buf, ret,
> + CDNS_DPN_B0_CONFIG(i) + j * 4);
> + }
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nDPn B1 Registers\n");
> + for (i = 0; i < 7; i++) {
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nDP-%d\n", i);
> +
> + for (j = 0; j < 6; j++)
> + ret += cdns_sprintf(cdns, buf, ret,
> + CDNS_DPN_B1_CONFIG(i) + j * 4);
> + }
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nDPn Control Registers\n");
> + for (i = 0; i < 7; i++)
> + ret += cdns_sprintf(cdns, buf, ret,
> + CDNS_PORTCTRL + i * CDNS_PORT_OFFSET);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nPDIn Config Registers\n");
> + for (i = 0; i < 7; i++)
> + ret += cdns_sprintf(cdns, buf, ret, CDNS_PDI_CONFIG(i));
> +
> + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> + kfree(buf);
> +
> + return ret;
> +}
> +
> +static const struct file_operations cdns_reg_fops = {
> + .open = simple_open,
> + .read = cdns_reg_read,
> + .llseek = default_llseek,
> +};

DEFINE_SHOW_ATTRIBUTE()?

thanks,

greg k-h

2019-07-26 14:11:17

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [RFC PATCH 37/40] soundwire: cadence_master: add hw_reset capability in debugfs

On Thu, Jul 25, 2019 at 06:40:29PM -0500, Pierre-Louis Bossart wrote:
> This is to kick devices into reset and see what software does
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index fa7230b0f200..53278aa2436f 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -331,6 +331,25 @@ static const struct file_operations cdns_reg_fops = {
> .llseek = default_llseek,
> };
>
> +static int cdns_hw_reset(void *data, u64 value)
> +{
> + struct sdw_cdns *cdns = data;
> + int ret;
> +
> + if (value != 1)
> + return 0;
> +
> + dev_info(cdns->dev, "starting link hw_reset\n");
> +
> + ret = sdw_cdns_exit_reset(cdns);
> +
> + dev_info(cdns->dev, "link hw_reset done\n");

Do not be noisy for when things always go right. This looks like
debuggging code, please remove.

> +
> + return ret;
> +}
> +
> +DEFINE_DEBUGFS_ATTRIBUTE(cdns_hw_reset_fops, NULL, cdns_hw_reset, "%llu\n");
> +
> /**
> * sdw_cdns_debugfs_init() - Cadence debugfs init
> * @cdns: Cadence instance
> @@ -339,6 +358,9 @@ static const struct file_operations cdns_reg_fops = {
> void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root)
> {
> debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);
> +
> + debugfs_create_file_unsafe("cdns-hw-reset", 0200, root, cdns,
> + &cdns_hw_reset_fops);

Why unsafe?

thanks,

greg k-h

2019-07-26 14:13:57

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 16/40] soundwire: cadence_master: improve startup sequence with link hw_reset


>> +static int do_reset(struct sdw_cdns *cdns)
>> +{
>> + int ret;
>> +
>> + /* program maximum length reset to be safe */
>> + cdns_updatel(cdns, CDNS_MCP_CONTROL,
>> + CDNS_MCP_CONTROL_RST_DELAY,
>> + CDNS_MCP_CONTROL_RST_DELAY);
>> +
>> + /* use hardware generated reset */
>> + cdns_updatel(cdns, CDNS_MCP_CONTROL,
>> + CDNS_MCP_CONTROL_HW_RST,
>> + CDNS_MCP_CONTROL_HW_RST);
>> +
>> + /* enable bus operations with clock and data */
>> + cdns_updatel(cdns, CDNS_MCP_CONFIG,
>> + CDNS_MCP_CONFIG_OP,
>> + CDNS_MCP_CONFIG_OP_NORMAL);
>> +
>> + /* commit changes */
>> + ret = cdns_update_config(cdns);
>> +
>> + return ret;
>
> + return cdns_update_config(cdns);
>
> and remove the "ret" variable.

Yes, it's the same issue as previously reported. will fix.

2019-07-26 14:16:03

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 20/40] soundwire: prototypes for suspend/resume



On 7/26/19 5:04 AM, Cezary Rojewski wrote:
> On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
>> Signed-off-by: Pierre-Louis Bossart
>> <[email protected]>
>> ---
>>   drivers/soundwire/cadence_master.h | 3 +++
>>   1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/soundwire/cadence_master.h
>> b/drivers/soundwire/cadence_master.h
>> index c0bf6ff00a44..d375bbfead18 100644
>> --- a/drivers/soundwire/cadence_master.h
>> +++ b/drivers/soundwire/cadence_master.h
>> @@ -165,6 +165,9 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
>>   void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
>> +int sdw_cdns_suspend(struct sdw_cdns *cdns);
>> +bool sdw_cdns_check_resume_status(struct sdw_cdns *cdns);
>> +
>>   int sdw_cdns_get_stream(struct sdw_cdns *cdns,
>>               struct sdw_cdns_streams *stream,
>>               u32 ch, u32 dir);
>>
>
> No commit message, guess it's SQUASHME commit and shouldn't be part of
> overall series.

I can't recall why it's separate, will look into this. Thanks.

2019-07-26 14:24:57

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 24/40] soundwire: cadence_master: use BIOS defaults for frame shape



On 7/26/19 5:20 AM, Cezary Rojewski wrote:
> On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
>> +static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
>> +{
>> +    u32 val;
>> +    int c;
>> +    int r;
>> +
>> +    r = sdw_find_row_index(n_rows);
>> +    c = sdw_find_col_index(n_cols);
>> +
>> +    val = (r << 3) | c;
>> +
>> +    return val;
>> +}
>> +
>>   /**
>>    * sdw_cdns_init() - Cadence initialization
>>    * @cdns: Cadence instance
>> @@ -977,7 +990,9 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
>>       cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
>>       /* Set the default frame shape */
>> -    cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT,
>> CDNS_DEFAULT_FRAME_SHAPE);
>> +    val = cdns_set_default_frame_shape(prop->default_row,
>> +                       prop->default_col);
>> +    cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT, val);
>>       /* Set SSP interval to default value */
>>       cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, CDNS_DEFAULT_SSP_INTERVAL);
>>
>
> Suggestion:
> declare "generic" _get_frame_frame(rows, cols) instead and let it do the
> bitwise operations for you. Pretty sure this won't be the only place in
> code where reg value for frame_shape needs to be prepared.
>
> Said function could be as simple as:
> return (row << 3) | cols;
> +inline flag
>
> i.e. could be even a macro..
>
> Otherwise modify _set_default_frame_shape to simply:
> return (r << 3) | c
>
> without involving additional local val variable (I don't really see the
> point for any locals there though).

what this function does is take the standard-defined offsets for row and
column and stores them in a Cadence-defined register. I think we can
probably use a macro to remove the magic '3' value, but there are limits
to what we can simplify. I should probably add comments so that people
figure it out.

2019-07-26 14:27:42

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 26/40] soundwire: cadence_master: fix divider setting in clock register



On 7/26/19 12:19 AM, Bard liao wrote:
>
> On 7/26/2019 7:40 AM, Pierre-Louis Bossart wrote:
>> From: Rander Wang <[email protected]>
>>
>> The existing code uses an OR operation which would mix the original
>> divider setting with the new one, resulting in an invalid
>> configuration that can make codecs hang.
>>
>> Add the mask definition and use cdns_updatel to update divider
>>
>> Signed-off-by: Rander Wang <[email protected]>
>> Signed-off-by: Pierre-Louis Bossart
>> <[email protected]>
>> ---
>>   drivers/soundwire/cadence_master.c | 12 +++++++-----
>>   1 file changed, 7 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/soundwire/cadence_master.c
>> b/drivers/soundwire/cadence_master.c
>> index 10ebcef2e84e..18c6ac026e85 100644
>> --- a/drivers/soundwire/cadence_master.c
>> +++ b/drivers/soundwire/cadence_master.c
>> @@ -57,6 +57,7 @@
>>   #define CDNS_MCP_SSP_CTRL1            0x28
>>   #define CDNS_MCP_CLK_CTRL0            0x30
>>   #define CDNS_MCP_CLK_CTRL1            0x38
>> +#define CDNS_MCP_CLK_MCLKD_MASK        GENMASK(7, 0)
>>   #define CDNS_MCP_STAT                0x40
>> @@ -988,9 +989,11 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
>>       /* Set clock divider */
>>       divider    = (prop->mclk_freq / prop->max_clk_freq) - 1;
>>       val = cdns_readl(cdns, CDNS_MCP_CLK_CTRL0);
>
>
> Do we still need to read cdns_readl(cdns, CDNS_MCP_CLK_CTRL0)
>
> after this change?

no I don't think we do indeed.
>
>
>> -    val |= divider;
>> -    cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
>> -    cdns_writel(cdns, CDNS_MCP_CLK_CTRL1, val);
>> +
>> +    cdns_updatel(cdns, CDNS_MCP_CLK_CTRL0,
>> +             CDNS_MCP_CLK_MCLKD_MASK, divider);
>> +    cdns_updatel(cdns, CDNS_MCP_CLK_CTRL1,
>> +             CDNS_MCP_CLK_MCLKD_MASK, divider);
>>       pr_err("plb: mclk %d max_freq %d divider %d register %x\n",
>>              prop->mclk_freq,

and this log needs to go away or done in a better way, I missed this.

>> @@ -1064,8 +1067,7 @@ int cdns_bus_conf(struct sdw_bus *bus, struct
>> sdw_bus_params *params)
>>           mcp_clkctrl_off = CDNS_MCP_CLK_CTRL0;
>>       mcp_clkctrl = cdns_readl(cdns, mcp_clkctrl_off);
>
>
> Same here.

yep.

>
>
>> -    mcp_clkctrl |= divider;
>> -    cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl);
>> +    cdns_updatel(cdns, mcp_clkctrl_off, CDNS_MCP_CLK_MCLKD_MASK,
>> divider);
>>       pr_err("plb: mclk * 2 %d curr_dr_freq %d divider %d register %x\n",
>>              prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR,
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 14:42:40

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 27/40] soundwire: Add Intel resource management algorithm



On 7/26/19 6:07 AM, Cezary Rojewski wrote:
> On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
>> This algorithm computes bus parameters like clock frequency, frame
>> shape and port transport parameters based on active stream(s) running
>> on the bus.
>>
>> This implementation is optimal for Intel platforms. Developers can
>> also implement their own .compute_params() callback for specific
>> resource management algorithm.
>>
>> Credits: this patch is based on an earlier internal contribution by
>> Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. All hard-coded
>> values were removed from the initial contribution to use BIOS
>> information instead.
>>
>> FIXME: remove checkpatch report
>> WARNING: Reusing the krealloc arg is almost always a bug
>> +            group->rates = krealloc(group->rates,
>>
>> Signed-off-by: Pierre-Louis Bossart
>> <[email protected]>
>
> Could you specify the requirements and limitations for this algorithm?
> Last year I written calc for Linux based on Windows (please don't burn
> me here) equivalent though said requirements/ limitiations might have
> changed and nothing is valid any longer.

The frame shape typically only changes by doubling the number of
columns, and the priority is given to PDM streams which use columns.
It's hard to document this on a public mailing list, it'd require making
references to a spec that's only available to MIPI members.

>
> I remember that some parts of specification overcomplicated the
> calculator and due to actual, realtime usecases it could be greatly
> simplified (that's why I mention that my work is probably no longer
> valid). However, these details would help me in reviewing your
> implementation and providing suggestions.

To the best of my knowledge, the algorithm follows a script that is used
for both Windows and Linux. The code was initially written by Vinod and
team, and I am not aware of simplifications.
There a simplifications that are possible, e.g. we don't support PDM for
now and the notion of grouping is not needed, but we have to carefully
balance 'optimization' with 'introducing bugs'. if this algorithm craps
out then the entire bus operation is in the weeds.

If we really want people to experiment and get a feel for the
performance of the algorithm, we should really provide a UI where the
stream parameters can be entered and visually check what the algorithm
is doing. I have a solution that shows the bits based on the stream
parameters (need to make it available e.g. in Python), if we connected
it with the automatic bit allocation it'd be very useful.

> And yes, "Frame shape calculator" probably suits this better.
> Though this might be just a preference thingy : )

Resource management is indeed a bit vague. But frame shape calculator is
not quite right. The algorithm will find the frame shape that is
required for the current bandwidth, but will also allocate the bitSlots
in that frame. In MIPI circles we talk about bitSlot allocation.

2019-07-26 14:44:59

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 21/40] soundwire: export helpers to find row and column values

On Thu, Jul 25, 2019 at 06:40:13PM -0500, Pierre-Louis Bossart wrote:
> Add a prefix for common tables and export 2 helpers to set the frame
> shapes based on row/col values.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/bus.h | 7 +++++--
> drivers/soundwire/stream.c | 14 ++++++++------
> 2 files changed, 13 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
> index 06ac4adb0074..c57c9c23f6ca 100644
> --- a/drivers/soundwire/bus.h
> +++ b/drivers/soundwire/bus.h
> @@ -73,8 +73,11 @@ struct sdw_msg {
>
> #define SDW_DOUBLE_RATE_FACTOR 2
>
> -extern int rows[SDW_FRAME_ROWS];
> -extern int cols[SDW_FRAME_COLS];
> +extern int sdw_rows[SDW_FRAME_ROWS];
> +extern int sdw_cols[SDW_FRAME_COLS];

So these arrays actually have to be exported? In the current (5.2) sources they
seem to only be used in stream.c, maybe make them static there?

> +
> +int sdw_find_row_index(int row);
> +int sdw_find_col_index(int col);
>
> /**
> * sdw_port_runtime: Runtime port parameters for Master or Slave
> diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
> index a0476755a459..53f5e790fcd7 100644
> --- a/drivers/soundwire/stream.c
> +++ b/drivers/soundwire/stream.c
> @@ -21,37 +21,39 @@
> * The rows are arranged as per the array index value programmed
> * in register. The index 15 has dummy value 0 in order to fill hole.
> */
> -int rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,
> +int sdw_rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,
> 96, 100, 120, 128, 150, 160, 250, 0,
> 192, 200, 240, 256, 72, 144, 90, 180};
>
> -int cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};
> +int sdw_cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};
>
> -static int sdw_find_col_index(int col)
> +int sdw_find_col_index(int col)
> {
> int i;
>
> for (i = 0; i < SDW_FRAME_COLS; i++) {
> - if (cols[i] == col)
> + if (sdw_cols[i] == col)
> return i;
> }
>
> pr_warn("Requested column not found, selecting lowest column no: 2\n");
> return 0;
> }
> +EXPORT_SYMBOL(sdw_find_col_index);
>
> -static int sdw_find_row_index(int row)
> +int sdw_find_row_index(int row)
> {
> int i;
>
> for (i = 0; i < SDW_FRAME_ROWS; i++) {
> - if (rows[i] == row)
> + if (sdw_rows[i] == row)
> return i;
> }
>
> pr_warn("Requested row not found, selecting lowest row no: 48\n");
> return 0;
> }
> +EXPORT_SYMBOL(sdw_find_row_index);
>
> static int _sdw_program_slave_port_params(struct sdw_bus *bus,
> struct sdw_slave *slave,
> --
> 2.20.1
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 14:47:56

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 31/40] soundwire: intel: move shutdown() callback and don't export symbol



On 7/26/19 5:38 AM, Cezary Rojewski wrote:
> On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
>> +void intel_shutdown(struct snd_pcm_substream *substream,
>> +            struct snd_soc_dai *dai)
>> +{
>> +    struct sdw_cdns_dma_data *dma;
>> +
>> +    dma = snd_soc_dai_get_dma_data(dai, substream);
>> +    if (!dma)
>> +        return;
>> +
>> +    snd_soc_dai_set_dma_data(dai, substream, NULL);
>> +    kfree(dma);
>> +}
>
> Correct me if I'm wrong, but do we really need to _get_dma_ here?
> _set_dma_ seems bulletproof, same for kfree.

I must admit I have no idea why we have a reference to DMAs here, this
looks like an abuse to store a dai-specific context, and the initial
test looks like copy-paste to detect invalid configs, as done in other
callbacks. Vinod and Sanyog might have more history than me here.

2019-07-26 14:57:29

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 32/40] soundwire: intel: add helper for initialization



On 7/26/19 5:42 AM, Cezary Rojewski wrote:
> On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
>> Move code to helper for reuse in power management routines
>>
>> Signed-off-by: Pierre-Louis Bossart
>> <[email protected]>
>> ---
>>   drivers/soundwire/intel.c | 16 +++++++++++-----
>>   1 file changed, 11 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
>> index c40ab443e723..215dc81cdf73 100644
>> --- a/drivers/soundwire/intel.c
>> +++ b/drivers/soundwire/intel.c
>> @@ -984,6 +984,15 @@ static struct sdw_master_ops sdw_intel_ops = {
>>       .post_bank_switch = intel_post_bank_switch,
>>   };
>> +static int intel_init(struct sdw_intel *sdw)
>> +{
>> +    /* Initialize shim and controller */
>> +    intel_link_power_up(sdw);
>> +    intel_shim_init(sdw);
>> +
>> +    return sdw_cdns_init(&sdw->cdns);
>> +}
>
> Why don't we check polling status for _link_power_up? I've already met
> slow starting devices in the past. If polling fails and -EAGAIN is
> returned, flow of initialization should react appropriately e.g. poll
> till MAX_TIMEOUT of some sort -or- collapse.

The code does what it states, it initializes the Intel and Cadence IPs.

What you are referring to is a different problem: once the bus starts,
then Slave devices will report as attached, and will be enumerated. This
will take time. The devices I tested show up immediately and within a
couple of ms the bus is operational. But MIPI allows to the sync to take
up to 4096 frames, which is 85ms with a 48kHz frame rate, so yes we do
need to look into this.

We currently do not have a notification that tells us the bus is back to
normal, that's a design flaw - see the last patch of the series where I
kicked the can down the road but adding an artificial delay.

So yes good point indeed but on the wrong patch :-)

2019-07-26 15:27:24

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 21/40] soundwire: export helpers to find row and column values



On 7/26/19 9:43 AM, Guennadi Liakhovetski wrote:
> On Thu, Jul 25, 2019 at 06:40:13PM -0500, Pierre-Louis Bossart wrote:
>> Add a prefix for common tables and export 2 helpers to set the frame
>> shapes based on row/col values.
>>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/bus.h | 7 +++++--
>> drivers/soundwire/stream.c | 14 ++++++++------
>> 2 files changed, 13 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
>> index 06ac4adb0074..c57c9c23f6ca 100644
>> --- a/drivers/soundwire/bus.h
>> +++ b/drivers/soundwire/bus.h
>> @@ -73,8 +73,11 @@ struct sdw_msg {
>>
>> #define SDW_DOUBLE_RATE_FACTOR 2
>>
>> -extern int rows[SDW_FRAME_ROWS];
>> -extern int cols[SDW_FRAME_COLS];
>> +extern int sdw_rows[SDW_FRAME_ROWS];
>> +extern int sdw_cols[SDW_FRAME_COLS];
>
> So these arrays actually have to be exported? In the current (5.2) sources they
> seem to only be used in stream.c, maybe make them static there?
>
>> +
>> +int sdw_find_row_index(int row);
>> +int sdw_find_col_index(int col);

yes, they need to be exported, they are used by the allocation algorithm
(in Patch 27).
Others will need this for non-Intel solutions, it's really a part of the
standard definition and should be shared.
I can improve the commit message to make this explicit.

2019-07-26 15:30:52

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 01/40] soundwire: add debugfs support


>> diff --git a/drivers/soundwire/debugfs.c b/drivers/soundwire/debugfs.c
>> new file mode 100644
>> index 000000000000..8d86e100516e
>> --- /dev/null
>> +++ b/drivers/soundwire/debugfs.c
>> @@ -0,0 +1,156 @@
>> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
>
> No, for debugfs-specific code, that dual license makes no sense, right?
> Don't cargo-cult SPDX identifiers please.

It's a miss, I used EXPORT_GPL and missed this line, will fix.

>
>> +// Copyright(c) 2017-19 Intel Corporation.
>
> Spell the year out fully unless you want lawyers knocking on your door :)

haha, will fix.

>
>> +
>> +#include <linux/device.h>
>> +#include <linux/debugfs.h>
>> +#include <linux/mod_devicetable.h>
>> +#include <linux/slab.h>
>> +#include <linux/soundwire/sdw.h>
>> +#include <linux/soundwire/sdw_registers.h>
>> +#include "bus.h"
>> +
>> +#ifdef CONFIG_DEBUG_FS
>> +struct dentry *sdw_debugfs_root;
>> +#endif
>
> This whole file is not built if that option is not enabled, so why the
> #ifdef?

Ah, will look into this, thanks!

2019-07-26 15:36:10

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 04/40] soundwire: intel: add debugfs register dump


>> +static const struct file_operations intel_reg_fops = {
>> + .open = simple_open,
>> + .read = intel_reg_read,
>> + .llseek = default_llseek,
>> +};
>
> DEFINE_SIMPLE_ATTRIBUTE()?

yes

>
>> +
>> +static void intel_debugfs_init(struct sdw_intel *sdw)
>> +{
>> + struct dentry *root = sdw->cdns.bus.debugfs;
>> +
>> + if (!root)
>> + return;
>> +
>> + sdw->fs = debugfs_create_dir("intel-sdw", root);
>> + if (IS_ERR_OR_NULL(sdw->fs)) {
>> + dev_err(sdw->cdns.dev, "debugfs root creation failed\n");
>
> No, come on, don't do that. I've been sweeping the kernel tree to
> remove this anti-pattern.
>
> The debugfs core will print an error if you got something wrong, just
> call the function and move on, you NEVER need to check the return value
> of a debugfs call.

Yes, sorry to make your blood pressure go up... I missed this one in the
cleanups yesterday. will fix.

2019-07-26 15:37:22

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 02/40] soundwire: cadence_master: add debugfs register dump


>> +static const struct file_operations cdns_reg_fops = {
>> + .open = simple_open,
>> + .read = cdns_reg_read,
>> + .llseek = default_llseek,
>> +};
>
> DEFINE_SHOW_ATTRIBUTE()?

I remember looking at this but can't recall why I left it this way.
That was before my Summer break so will relook, thanks for suggesting this.

2019-07-26 15:44:31

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 27/40] soundwire: Add Intel resource management algorithm

On Thu, Jul 25, 2019 at 06:40:19PM -0500, Pierre-Louis Bossart wrote:
> This algorithm computes bus parameters like clock frequency, frame
> shape and port transport parameters based on active stream(s) running
> on the bus.
>
> This implementation is optimal for Intel platforms. Developers can
> also implement their own .compute_params() callback for specific
> resource management algorithm.
>
> Credits: this patch is based on an earlier internal contribution by
> Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. All hard-coded
> values were removed from the initial contribution to use BIOS
> information instead.
>
> FIXME: remove checkpatch report
> WARNING: Reusing the krealloc arg is almost always a bug
> + group->rates = krealloc(group->rates,
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/Makefile | 2 +-
> drivers/soundwire/algo_dynamic_allocation.c | 403 ++++++++++++++++++++
> drivers/soundwire/bus.c | 3 +
> drivers/soundwire/bus.h | 46 ++-
> drivers/soundwire/stream.c | 20 +
> include/linux/soundwire/sdw.h | 5 +
> 6 files changed, 476 insertions(+), 3 deletions(-)
> create mode 100644 drivers/soundwire/algo_dynamic_allocation.c
>
> diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile
> index 88990cac48a7..f59a9d4a28fd 100644
> --- a/drivers/soundwire/Makefile
> +++ b/drivers/soundwire/Makefile
> @@ -5,7 +5,7 @@
>
> #Bus Objs
> soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o \
> - debugfs.o
> + debugfs.o algo_dynamic_allocation.o
>
> obj-$(CONFIG_SOUNDWIRE_BUS) += soundwire-bus.o
>
> diff --git a/drivers/soundwire/algo_dynamic_allocation.c b/drivers/soundwire/algo_dynamic_allocation.c
> new file mode 100644
> index 000000000000..89edb39162b8
> --- /dev/null
> +++ b/drivers/soundwire/algo_dynamic_allocation.c
> @@ -0,0 +1,403 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> +// Copyright(c) 2015-18 Intel Corporation.
> +
> +/*
> + * Bandwidth management algorithm based on 2^n gears
> + *
> + */
> +
> +#include <linux/device.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/slab.h>
> +#include <linux/soundwire/sdw.h>
> +#include "bus.h"
> +
> +#define SDW_STRM_RATE_GROUPING 1
> +
> +struct sdw_group_params {
> + unsigned int rate;
> + int full_bw;
> + int payload_bw;
> + int hwidth;
> +};
> +
> +struct sdw_group {
> + unsigned int count;
> + unsigned int max_size;
> + unsigned int *rates;
> +};
> +
> +struct sdw_transport_data {
> + int hstart;
> + int hstop;
> + int block_offset;
> + int sub_block_offset;
> +};
> +
> +static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
> + struct sdw_transport_data *t_data)
> +{
> + struct sdw_slave_runtime *s_rt = NULL;

Superfluous initialisation.

> + struct sdw_port_runtime *p_rt;
> + int port_bo, sample_int;
> + unsigned int rate, bps, ch = 0;

ditto for ch

> +
> + port_bo = t_data->block_offset;
> +
> + list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
> + rate = m_rt->stream->params.rate;
> + bps = m_rt->stream->params.bps;
> + sample_int = (m_rt->bus->params.curr_dr_freq / rate);
> +
> + list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
> + ch = sdw_ch_mask_to_ch(p_rt->ch_mask);
> +
> + sdw_fill_xport_params(&p_rt->transport_params,
> + p_rt->num, true,
> + SDW_BLK_GRP_CNT_1,
> + sample_int, port_bo, port_bo >> 8,
> + t_data->hstart,
> + t_data->hstop,

I think the above two lines could fit in one

> + (SDW_BLK_GRP_CNT_1 * ch), 0x0);

superfluous parentheses

> +
> + sdw_fill_port_params(&p_rt->port_params,
> + p_rt->num, bps,
> + SDW_PORT_FLOW_MODE_ISOCH,
> + SDW_PORT_DATA_MODE_NORMAL);
> +
> + port_bo += bps * ch;
> + }
> + }
> +}
> +
> +static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
> + struct sdw_group_params *params,
> + int port_bo, int hstop)
> +{
> + struct sdw_transport_data t_data = {0};
> + struct sdw_port_runtime *p_rt;
> + struct sdw_bus *bus = m_rt->bus;
> + int sample_int, hstart = 0;

superfluous initialisation

> + unsigned int rate, bps, ch, no_ch;
> +
> + rate = m_rt->stream->params.rate;
> + bps = m_rt->stream->params.bps;
> + ch = m_rt->ch_count;
> + sample_int = (bus->params.curr_dr_freq / rate);

superfluous parentheses

> +
> + if (rate != params->rate)
> + return;
> +
> + t_data.hstop = hstop;
> + hstart = hstop - params->hwidth + 1;
> + t_data.hstart = hstart;
> +
> + list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
> + no_ch = sdw_ch_mask_to_ch(p_rt->ch_mask);
> +
> + sdw_fill_xport_params(&p_rt->transport_params, p_rt->num,
> + true, SDW_BLK_GRP_CNT_1, sample_int,
> + port_bo, port_bo >> 8, hstart, hstop,
> + (SDW_BLK_GRP_CNT_1 * no_ch), 0x0);

superfluous parentheses

> +
> + sdw_fill_port_params(&p_rt->port_params,
> + p_rt->num, bps,
> + SDW_PORT_FLOW_MODE_ISOCH,
> + SDW_PORT_DATA_MODE_NORMAL);
> +
> + /* Check for first entry */
> + if (!(p_rt == list_first_entry(&m_rt->port_list,
> + struct sdw_port_runtime,
> + port_node))) {

you wanted to write "if (p_rt != ...)"

> + port_bo += bps * ch;
> + continue;
> + }
> +
> + t_data.hstart = hstart;
> + t_data.hstop = hstop;

You already set these two above

> + t_data.block_offset = port_bo;
> + t_data.sub_block_offset = 0;
> + port_bo += bps * ch;
> + }
> +
> + sdw_compute_slave_ports(m_rt, &t_data);
> +}
> +
> +static void _sdw_compute_port_params(struct sdw_bus *bus,
> + struct sdw_group_params *params, int count)
> +{
> + struct sdw_master_runtime *m_rt = NULL;

superfluous initialisation

> + int hstop = bus->params.col - 1;
> + int block_offset, port_bo, i;
> +
> + /* Run loop for all groups to compute transport parameters */
> + for (i = 0; i < count; i++) {
> + port_bo = 1;
> + block_offset = 1;
> +
> + list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
> + sdw_compute_master_ports(m_rt, &params[i],
> + port_bo, hstop);
> +
> + block_offset += m_rt->ch_count *
> + m_rt->stream->params.bps;
> + port_bo = block_offset;
> + }
> +
> + hstop = hstop - params[i].hwidth;

hstop -= ...

> + }
> +}
> +
> +static int sdw_compute_group_params(struct sdw_bus *bus,
> + struct sdw_group_params *params,
> + int *rates, int count)
> +{
> + struct sdw_master_runtime *m_rt = NULL;

ditto

> + int sel_col = bus->params.col;
> + unsigned int rate, bps, ch;
> + int i, column_needed = 0;
> +
> + /* Calculate bandwidth per group */
> + for (i = 0; i < count; i++) {
> + params[i].rate = rates[i];
> + params[i].full_bw = bus->params.curr_dr_freq / params[i].rate;
> + }
> +
> + list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
> + rate = m_rt->stream->params.rate;
> + bps = m_rt->stream->params.bps;
> + ch = m_rt->ch_count;
> +
> + for (i = 0; i < count; i++) {
> + if (rate == params[i].rate)
> + params[i].payload_bw += bps * ch;

I don't know about the algorithm, rates can repeat, right? So you cannot break
out of the loop here once you found one match?

> + }
> + }
> +
> + for (i = 0; i < count; i++) {
> + params[i].hwidth = (sel_col *
> + params[i].payload_bw + params[i].full_bw - 1) /
> + params[i].full_bw;
> +
> + column_needed += params[i].hwidth;
> + }
> +
> + if (column_needed > sel_col - 1)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int sdw_add_element_group_count(struct sdw_group *group,
> + unsigned int rate)
> +{
> + int num = group->count;
> + int i;
> +
> + for (i = 0; i <= num; i++) {
> + if (rate == group->rates[i])

Are you sure this is correct? You actually check count + 1 rates - from 0
to count inclusively. I think this isn't what you wanted to do, so my
proposal below only checks count rates.

> + break;
> +
> + if (i != num)
> + continue;
> +
> + if (group->count >= group->max_size) {
> + group->max_size += 1;
> + group->rates = krealloc(group->rates,
> + (sizeof(int) * group->max_size),
> + GFP_KERNEL);
> + if (!group->rates)
> + return -ENOMEM;
> + }
> +
> + group->rates[group->count++] = rate;
> + }

How about this:

for (i = 0; i < num; i++)
if (rate == group->rates[i])
return 0;

if (group->count >= group->max_size) {
group->max_size += 1;
group->rates = krealloc(group->rates,
(sizeof(int) * group->max_size),
GFP_KERNEL);
if (!group->rates)
return -ENOMEM;
}

group->rates[group->count++] = rate;

return 0;

> +
> + return 0;
> +}
> +
> +static int sdw_get_group_count(struct sdw_bus *bus,
> + struct sdw_group *group)
> +{
> + struct sdw_master_runtime *m_rt;
> + unsigned int rate;
> + int ret = 0;
> +
> + group->count = 0;
> + group->max_size = SDW_STRM_RATE_GROUPING;
> + group->rates = kcalloc(group->max_size, sizeof(int), GFP_KERNEL);
> + if (!group->rates)
> + return -ENOMEM;
> +
> + list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
> + rate = m_rt->stream->params.rate;
> + if (m_rt == list_first_entry(&bus->m_rt_list,
> + struct sdw_master_runtime,
> + bus_node)) {
> + group->rates[group->count++] = rate;
> +
> + } else {
> + ret = sdw_add_element_group_count(group, rate);
> + if (ret < 0)

Actually it looks like you should free rates here? I see that not doing this
makes the caller function below easier, but I'd say this is more error-
prone... Up to you but I'd go the "safe" way - if it fails, it frees itself,
if it succeeds - it's freed elsewhere.

> + return ret;
> + }
> + }
> +
> + return ret;

I think this will always return 0 here, so you don't need the "ret"
variable in the function scope, you only need it in the "else"
scope above.

> +}
> +
> +/**
> + * sdw_compute_port_params: Compute transport and port parameters
> + *
> + * @bus: SDW Bus instance
> + */
> +static int sdw_compute_port_params(struct sdw_bus *bus)
> +{
> + struct sdw_group_params *params = NULL;
> + struct sdw_group group;
> + int ret;
> +
> + ret = sdw_get_group_count(bus, &group);
> + if (ret < 0)
> + goto out;
> +
> + if (group.count == 0)
> + goto out;
> +
> + params = kcalloc(group.count, sizeof(*params), GFP_KERNEL);
> + if (!params) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + /* Compute transport parameters for grouped streams */
> + ret = sdw_compute_group_params(bus, params,
> + &group.rates[0], group.count);
> + if (ret < 0)
> + goto out;
> +
> + _sdw_compute_port_params(bus, params, group.count);
> +
> +out:
> + kfree(params);
> + kfree(group.rates);

Depending whether or not you change the code above, this might change
too.

> +
> + return ret;
> +}
> +
> +static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq)
> +{
> + struct sdw_master_prop *prop = &bus->prop;
> + int frame_int, frame_freq;
> + int r, c;
> +
> + for (c = 0; c < SDW_FRAME_COLS; c++) {
> + for (r = 0; r < SDW_FRAME_ROWS; r++) {
> + if (sdw_rows[r] != prop->default_row ||
> + sdw_cols[c] != prop->default_col)
> + continue;
> +
> + frame_int = sdw_rows[r] * sdw_cols[c];
> + frame_freq = clk_freq / frame_int;
> +
> + if ((clk_freq - (frame_freq * SDW_FRAME_CTRL_BITS)) <
> + bus->params.bandwidth)
> + continue;
> +
> + bus->params.row = sdw_rows[r];
> + bus->params.col = sdw_cols[c];
> + return 0;
> + }
> + }
> +
> + return -EINVAL;
> +}
> +
> +/**
> + * sdw_compute_bus_params: Compute bus parameters
> + *
> + * @bus: SDW Bus instance
> + */
> +static int sdw_compute_bus_params(struct sdw_bus *bus)
> +{
> + unsigned int max_dr_freq, curr_dr_freq = 0;
> + struct sdw_master_prop *mstr_prop = NULL;

superfluous initialisation

> + int i, clk_values, ret;
> + bool is_gear = false;
> + u32 *clk_buf;
> +
> + mstr_prop = &bus->prop;
> + if (!mstr_prop)

this is impossible, it's an address of bus->prop...

> + return -EINVAL;
> +
> + if (mstr_prop->num_clk_gears) {
> + clk_values = mstr_prop->num_clk_gears;
> + clk_buf = mstr_prop->clk_gears;
> + is_gear = true;
> + } else if (mstr_prop->num_clk_freq) {
> + clk_values = mstr_prop->num_clk_freq;
> + clk_buf = mstr_prop->clk_freq;
> + } else {
> + clk_values = 1;
> + clk_buf = NULL;
> + }
> +
> + max_dr_freq = mstr_prop->max_clk_freq * SDW_DOUBLE_RATE_FACTOR;
> +
> + for (i = 0; i < clk_values; i++) {
> + if (!clk_buf)
> + curr_dr_freq = max_dr_freq;
> + else
> + curr_dr_freq = (is_gear) ?

superfluous parentheses

> + (max_dr_freq >> clk_buf[i]) :

ditto

> + clk_buf[i] * SDW_DOUBLE_RATE_FACTOR;
> +
> + if (curr_dr_freq <= bus->params.bandwidth)
> + continue;
> +
> + break;

I think this is raw code, you'd actually want to write this as

if (curr_dr_freq > bus->params.bandwidth)
break;

> +
> + /*
> + * TODO: Check all the Slave(s) port(s) audio modes and find
> + * whether given clock rate is supported with glitchless
> + * transition.
> + */
> + }
> +
> + if (i == clk_values)
> + return -EINVAL;
> +
> + ret = sdw_select_row_col(bus, curr_dr_freq);
> + if (ret < 0)
> + return -EINVAL;
> +
> + bus->params.curr_dr_freq = curr_dr_freq;
> + return 0;
> +}
> +
> +/**
> + * sdw_compute_params: Compute bus, transport and port parameters
> + *
> + * @bus: SDW Bus instance
> + */
> +int sdw_compute_params(struct sdw_bus *bus)
> +{
> + int ret;
> +
> + /* Computes clock frequency, frame shape and frame frequency */
> + ret = sdw_compute_bus_params(bus);
> + if (ret < 0) {
> + dev_err(bus->dev, "Compute bus params failed: %d", ret);
> + return ret;
> + }
> +
> + /* Compute transport and port params */
> + ret = sdw_compute_port_params(bus);
> + if (ret < 0) {
> + dev_err(bus->dev, "Compute transport params failed: %d", ret);
> + return ret;
> + }
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(sdw_compute_params);
> diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
> index 2354675ef104..76a180578712 100644
> --- a/drivers/soundwire/bus.c
> +++ b/drivers/soundwire/bus.c
> @@ -51,6 +51,9 @@ int sdw_add_bus_master(struct sdw_bus *bus)
>
> bus->debugfs = sdw_bus_debugfs_init(bus);
>
> + if (!bus->compute_params)
> + bus->compute_params = &sdw_compute_params;

I think it is more usual to not use "&" with functions, but it's valid too

> +
> /*
> * Device numbers in SoundWire are 0 through 15. Enumeration device
> * number (0), Broadcast device number (15), Group numbers (12 and
> diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
> index c57c9c23f6ca..fdb7ce034fdf 100644
> --- a/drivers/soundwire/bus.h
> +++ b/drivers/soundwire/bus.h
> @@ -72,6 +72,7 @@ struct sdw_msg {
> };
>
> #define SDW_DOUBLE_RATE_FACTOR 2
> +#define SDW_STRM_RATE_GROUPING 1
>
> extern int sdw_rows[SDW_FRAME_ROWS];
> extern int sdw_cols[SDW_FRAME_COLS];
> @@ -157,9 +158,50 @@ int sdw_transfer_defer(struct sdw_bus *bus, struct sdw_msg *msg,
> int sdw_fill_msg(struct sdw_msg *msg, struct sdw_slave *slave,
> u32 addr, size_t count, u16 dev_num, u8 flags, u8 *buf);
>
> +/* Retrieve and return channel count from channel mask */
> +static inline int sdw_ch_mask_to_ch(int ch_mask)
> +{
> + int c = 0;

superfluous initialisation

> +
> + for (c = 0; ch_mask; ch_mask >>= 1)
> + c += ch_mask & 1;

isn't there a built-in or something to count set bits... You could use ffs() to
at least not loop 31 times for 0x80000000

> +
> + return c;
> +}
> +
> +/* Fill transport parameter data structure */
> +static inline void sdw_fill_xport_params(struct sdw_transport_params *params,
> + int port_num, bool grp_ctrl_valid,
> + int grp_ctrl, int sample_int,
> + int off1, int off2,
> + int hstart, int hstop,
> + int pack_mode, int lane_ctrl)
> +{
> + params->port_num = port_num;
> + params->blk_grp_ctrl_valid = grp_ctrl_valid;
> + params->blk_grp_ctrl = grp_ctrl;
> + params->sample_interval = sample_int;
> + params->offset1 = off1;
> + params->offset2 = off2;
> + params->hstart = hstart;
> + params->hstop = hstop;
> + params->blk_pkg_mode = pack_mode;
> + params->lane_ctrl = lane_ctrl;
> +}
> +
> +/* Fill port parameter data structure */
> +static inline void sdw_fill_port_params(struct sdw_port_params *params,
> + int port_num, int bps,
> + int flow_mode, int data_mode)
> +{
> + params->num = port_num;
> + params->bps = bps;
> + params->flow_mode = flow_mode;
> + params->data_mode = data_mode;
> +}
> +
> /* Read-Modify-Write Slave register */
> -static inline int
> -sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
> +static inline int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
> {
> int tmp;
>
> diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
> index 75b9ad1fb1a6..add7c121d084 100644
> --- a/drivers/soundwire/stream.c
> +++ b/drivers/soundwire/stream.c
> @@ -1485,6 +1485,16 @@ static int _sdw_prepare_stream(struct sdw_stream_runtime *stream)
> bus->params.bandwidth += m_rt->stream->params.rate *
> m_rt->ch_count * m_rt->stream->params.bps;
>
> + /* Compute params */
> + if (bus->compute_params) {
> + ret = bus->compute_params(bus);
> + if (ret < 0) {
> + dev_err(bus->dev,
> + "Compute params failed: %d", ret);
> + return ret;
> + }
> + }
> +
> /* Program params */
> ret = sdw_program_params(bus);
> if (ret < 0) {
> @@ -1704,6 +1714,16 @@ static int _sdw_deprepare_stream(struct sdw_stream_runtime *stream)
> bus->params.bandwidth -= m_rt->stream->params.rate *
> m_rt->ch_count * m_rt->stream->params.bps;
>
> + /* Compute params */
> + if (bus->compute_params) {
> + ret = bus->compute_params(bus);
> + if (ret < 0) {
> + dev_err(bus->dev,
> + "Compute params failed: %d", ret);
> + return ret;
> + }
> + }
> +
> /* Program params */
> ret = sdw_program_params(bus);
> if (ret < 0) {
> diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
> index b6acc436ac80..c7dfc824be80 100644
> --- a/include/linux/soundwire/sdw.h
> +++ b/include/linux/soundwire/sdw.h
> @@ -730,6 +730,7 @@ struct sdw_master_ops {
> * Bit set implies used number, bit clear implies unused number.
> * @bus_lock: bus lock
> * @msg_lock: message lock
> + * @compute_params: points to Bus resource management implementation
> * @ops: Master callback ops
> * @port_ops: Master port callback ops
> * @params: Current bus parameters
> @@ -752,6 +753,7 @@ struct sdw_bus {
> DECLARE_BITMAP(assigned, SDW_MAX_DEVICES);
> struct mutex bus_lock;
> struct mutex msg_lock;
> + int (*compute_params)(struct sdw_bus *bus);
> const struct sdw_master_ops *ops;
> const struct sdw_master_port_ops *port_ops;
> struct sdw_bus_params params;
> @@ -852,6 +854,9 @@ struct sdw_stream_runtime {
>
> struct sdw_stream_runtime *sdw_alloc_stream(char *stream_name);
> void sdw_release_stream(struct sdw_stream_runtime *stream);
> +
> +int sdw_compute_params(struct sdw_bus *bus);
> +
> int sdw_stream_add_master(struct sdw_bus *bus,
> struct sdw_stream_config *stream_config,
> struct sdw_port_config *port_config,
> --
> 2.20.1
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 16:17:50

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 09/40] soundwire: cadence_master: fix usage of CONFIG_UPDATE


>> @@ -758,15 +774,9 @@ static int _cdns_enable_interrupt(struct sdw_cdns
>> *cdns)
>>    */
>>   int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
>>   {
>> -    int ret;
>> -
>>       _cdns_enable_interrupt(cdns);
>> -    ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
>> -                 CDNS_MCP_CONFIG_UPDATE_BIT);
>> -    if (ret < 0)
>> -        dev_err(cdns->dev, "Config update timedout\n");
>> -    return ret;
> Should we add cdns_update_config() here?

indeed, this would be a good improvement. The code works because we
added the exit_reset() sequence which does call cdns_update_config(),
but better make this function self-contained. When we enable the
clock-stop mode we will not do this reset sequence.

2019-07-26 16:21:57

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 01/40] soundwire: add debugfs support



On 7/25/19 5:15 PM, Guennadi Liakhovetski wrote:
> Hi Pierre,
>
> A couple of nitpicks:

Thanks for the feedback!

>> create mode 100644 drivers/soundwire/debugfs.c
>
> [snip]
>
>> diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
>> index 3048ca153f22..06ac4adb0074 100644
>> --- a/drivers/soundwire/bus.h
>> +++ b/drivers/soundwire/bus.h
>> @@ -18,6 +18,30 @@ static inline int sdw_acpi_find_slaves(struct sdw_bus *bus)
>> void sdw_extract_slave_id(struct sdw_bus *bus,
>> u64 addr, struct sdw_slave_id *id);
>>
>> +#ifdef CONFIG_DEBUG_FS
>> +struct dentry *sdw_bus_debugfs_init(struct sdw_bus *bus);
>> +void sdw_bus_debugfs_exit(struct dentry *d);
>> +struct dentry *sdw_slave_debugfs_init(struct sdw_slave *slave);
>> +void sdw_slave_debugfs_exit(struct dentry *d);
>> +void sdw_debugfs_init(void);
>> +void sdw_debugfs_exit(void);
>> +#else
>> +struct dentry *sdw_bus_debugfs_init(struct sdw_bus *bus)
>> +{ return NULL; }
>
> static?
>
>> +
>> +void sdw_bus_debugfs_exit(struct dentry *d) {}
>> +
>> +struct dentry *sdw_slave_debugfs_init(struct sdw_slave *slave)
>> +{ return NULL; }
>> +
>> +void sdw_slave_debugfs_exit(struct dentry *d) {}
>> +
>> +void sdw_debugfs_init(void) {}
>> +
>> +void sdw_debugfs_exit(void) {}
>
> Same for all the above. You could also declare them inline, but I really hope
> the compiler will be smart enough to do that itself.

yes, I'll add static inline for all this.

>> +struct dentry *sdw_bus_debugfs_init(struct sdw_bus *bus)
>> +{
>> + struct dentry *d;
>
> I would remove the above
>
>> + char name[16];
>> +
>> + if (!sdw_debugfs_root)
>> + return NULL;
>> +
>> + /* create the debugfs master-N */
>> + snprintf(name, sizeof(name), "master-%d", bus->link_id);
>> + d = debugfs_create_dir(name, sdw_debugfs_root);
>> +
>> + return d;
>
> And just do
>
> + return debugfs_create_dir(name, sdw_debugfs_root);

yep, will do.

>> +static ssize_t sdw_sprintf(struct sdw_slave *slave,
>> + char *buf, size_t pos, unsigned int reg)
>> +{
>> + int value;
>> +
>> + value = sdw_read(slave, reg);
>
> I personally would join the two lines above, but that's just a personal
> preference.

I prefer splitting variables and code, I just can't mentally split the two.

>
>> +
>> + if (value < 0)
>> + return scnprintf(buf + pos, RD_BUF - pos, "%3x\tXX\n", reg);
>> + else
>
> I think it's advised to not use an else in such cases.
>
> Thanks
> Guennadi
>
>> + return scnprintf(buf + pos, RD_BUF - pos,
>> + "%3x\t%2x\n", reg, value);
>> +}

The intent was to provide a visual cue that the register is not
implemented, which is quite useful. Not all registers are mandatory and
not all vendors document the entire set of registers, so it's a good way
to figure things out. The value is not used for any functional purpose,
it's just a register dump for the integrator to look at. I'll add a note
to explain the idea.

2019-07-26 17:46:22

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [RFC PATCH 04/40] soundwire: intel: add debugfs register dump

On Fri, Jul 26, 2019 at 04:06:35PM +0200, Greg KH wrote:
> On Thu, Jul 25, 2019 at 06:39:56PM -0500, Pierre-Louis Bossart wrote:
> > Add debugfs file to dump the Intel SoundWire registers
> >
> > Credits: this patch is based on an earlier internal contribution by
> > Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. The main change
> > is the use of scnprintf to avoid known issues with snprintf.
> >
> > Signed-off-by: Pierre-Louis Bossart <[email protected]>
> > ---
> > drivers/soundwire/intel.c | 115 ++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 115 insertions(+)
> >
> > diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> > index 317873bc0555..aeadc341c0a3 100644
> > --- a/drivers/soundwire/intel.c
> > +++ b/drivers/soundwire/intel.c
> > @@ -6,6 +6,7 @@
> > */
> >
> > #include <linux/acpi.h>
> > +#include <linux/debugfs.h>
> > #include <linux/delay.h>
> > #include <linux/module.h>
> > #include <linux/interrupt.h>
> > @@ -16,6 +17,7 @@
> > #include <linux/soundwire/sdw.h>
> > #include <linux/soundwire/sdw_intel.h>
> > #include "cadence_master.h"
> > +#include "bus.h"
> > #include "intel.h"
> >
> > /* Intel SHIM Registers Definition */
> > @@ -98,6 +100,7 @@ struct sdw_intel {
> > struct sdw_cdns cdns;
> > int instance;
> > struct sdw_intel_link_res *res;
> > + struct dentry *fs;
> > };
> >
> > #define cdns_to_intel(_cdns) container_of(_cdns, struct sdw_intel, cdns)
> > @@ -161,6 +164,115 @@ static int intel_set_bit(void __iomem *base, int offset, u32 value, u32 mask)
> > return -EAGAIN;
> > }
> >
> > +/*
> > + * debugfs
> > + */
> > +
> > +#define RD_BUF (2 * PAGE_SIZE)
> > +
> > +static ssize_t intel_sprintf(void __iomem *mem, bool l,
> > + char *buf, size_t pos, unsigned int reg)
> > +{
> > + int value;
> > +
> > + if (l)
> > + value = intel_readl(mem, reg);
> > + else
> > + value = intel_readw(mem, reg);
> > +
> > + return scnprintf(buf + pos, RD_BUF - pos, "%4x\t%4x\n", reg, value);
> > +}
> > +
> > +static ssize_t intel_reg_read(struct file *file, char __user *user_buf,
> > + size_t count, loff_t *ppos)
> > +{
> > + struct sdw_intel *sdw = file->private_data;
> > + void __iomem *s = sdw->res->shim;
> > + void __iomem *a = sdw->res->alh;
> > + char *buf;
> > + ssize_t ret;
> > + int i, j;
> > + unsigned int links, reg;
> > +
> > + buf = kzalloc(RD_BUF, GFP_KERNEL);
> > + if (!buf)
> > + return -ENOMEM;
> > +
> > + links = intel_readl(s, SDW_SHIM_LCAP) & GENMASK(2, 0);
> > +
> > + ret = scnprintf(buf, RD_BUF, "Register Value\n");
> > + ret += scnprintf(buf + ret, RD_BUF - ret, "\nShim\n");
> > +
> > + for (i = 0; i < 4; i++) {
> > + reg = SDW_SHIM_LCAP + i * 4;
> > + ret += intel_sprintf(s, true, buf, ret, reg);
> > + }
> > +
> > + for (i = 0; i < links; i++) {
> > + ret += scnprintf(buf + ret, RD_BUF - ret, "\nLink%d\n", i);
> > + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLSCAP(i));
> > + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS0CM(i));
> > + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS1CM(i));
> > + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS2CM(i));
> > + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTLS3CM(i));
> > + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PCMSCAP(i));
> > +
> > + for (j = 0; j < 8; j++) {
> > + ret += intel_sprintf(s, false, buf, ret,
> > + SDW_SHIM_PCMSYCHM(i, j));
> > + ret += intel_sprintf(s, false, buf, ret,
> > + SDW_SHIM_PCMSYCHC(i, j));
> > + }
> > +
> > + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_PDMSCAP(i));
> > + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_IOCTL(i));
> > + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_CTMCTL(i));
> > + }
> > +
> > + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKEEN);
> > + ret += intel_sprintf(s, false, buf, ret, SDW_SHIM_WAKESTS);
> > +
> > + ret += scnprintf(buf + ret, RD_BUF - ret, "\nALH\n");
> > + for (i = 0; i < 8; i++)
> > + ret += intel_sprintf(a, true, buf, ret, SDW_ALH_STRMZCFG(i));
> > +
> > + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> > + kfree(buf);
> > +
> > + return ret;
> > +}
> > +
> > +static const struct file_operations intel_reg_fops = {
> > + .open = simple_open,
> > + .read = intel_reg_read,
> > + .llseek = default_llseek,
> > +};
>
> DEFINE_SIMPLE_ATTRIBUTE()?

Oops, I mean DEFINE_SHOW_ATTRIBUTE()?

2019-07-26 17:47:13

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 15/40] soundwire: cadence_master: handle multiple status reports per Slave


>> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
>> index 889fa2cd49ae..25d5c7267c15 100644
>> --- a/drivers/soundwire/cadence_master.c
>> +++ b/drivers/soundwire/cadence_master.c
>> @@ -643,13 +643,35 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
>>
>> /* first check if Slave reported multiple status */
>> if (set_status > 1) {
>> + u32 val;
>> +
>> dev_warn_ratelimited(cdns->dev,
>> - "Slave reported multiple Status: %d\n",
>> - mask);
>> - /*
>> - * TODO: we need to reread the status here by
>> - * issuing a PING cmd
>> - */
>> + "Slave %d reported multiple Status: %d\n",
>> + i, mask);
>> +
>> + /* re-check latest status extracted from PING commands */
>> + val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
>> + val >>= (i * 2);
>
> Superfluous parentheses.

Humm, I don't know my left from my right and I can't remember operator
precedence, so i'd rather make it explicit...

>
>> +
>> + switch (val & 0x3) {
>> + case 0:
>> + status[i] = SDW_SLAVE_UNATTACHED;
>> + break;
>> + case 1:
>> + status[i] = SDW_SLAVE_ATTACHED;
>> + break;
>> + case 2:
>> + status[i] = SDW_SLAVE_ALERT;
>> + break;
>> + default:
>
> There aren't many values left for the "default" case :-) But I'm not sure whether
> any of
>
> + case 3:
>
> or
>
> + case 3:
> + default:
>
> would improve readability.
>
> Thanks
> Guennadi
>
>> + status[i] = SDW_SLAVE_RESERVED;
>> + break;

Yes, those defaults are annoying. Some tools complain so I tend to leave
them.

2019-07-26 17:52:08

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 23/40] soundwire: stream: fix disable sequence



On 7/26/19 5:14 AM, Cezary Rojewski wrote:
> On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
>> -    return do_bank_switch(stream);
>> +    ret = do_bank_switch(stream);
>> +    if (ret < 0) {
>> +        dev_err(bus->dev, "Bank switch failed: %d\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    /* make sure alternate bank (previous current) is also disabled */
>> +    list_for_each_entry(m_rt, &stream->master_list, stream_node) {
>> +        bus = m_rt->bus;
>> +        /* Disable port(s) */
>> +        ret = sdw_enable_disable_ports(m_rt, false);
>> +        if (ret < 0) {
>> +            dev_err(bus->dev, "Disable port(s) failed: %d\n", ret);
>> +            return ret;
>> +        }
>> +    }
>> +
>> +    return 0;
>>   }
>>   /**
>>
>
> While not directly connected to this commit, I see that you do:
> link_for_each_entry(m_rt, &stream->master_list, stream_node)
>
> quite often in /stream.c code. Helpful macro would prove useful.

Yes, but the flip side is that people need to look at what the macro
does to figure it out, while everyone knows what list_for_each_entry()
means. Not sure about this one.
And on top of this we'll probably have to rework this code to have a
background copy of the current bank in the alternate bank so it'd rather
leave it simple for now.

2019-07-26 17:55:46

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 04/40] soundwire: intel: add debugfs register dump

On Fri, Jul 26, 2019 at 09:00:28AM -0500, Pierre-Louis Bossart wrote:
>
>
> On 7/26/19 4:35 AM, Cezary Rojewski wrote:
> > On 2019-07-26 01:39, Pierre-Louis Bossart wrote:
> > > +static void intel_debugfs_init(struct sdw_intel *sdw)
> > > +{
> > > +??? struct dentry *root = sdw->cdns.bus.debugfs;
> > > +
> > > +??? if (!root)
> > > +??????? return;
> > > +
> > > +??? sdw->fs = debugfs_create_dir("intel-sdw", root);
> > > +??? if (IS_ERR_OR_NULL(sdw->fs)) {
> > > +??????? dev_err(sdw->cdns.dev, "debugfs root creation failed\n");
> > > +??????? sdw->fs = NULL;
> > > +??????? return;
> > > +??? }
> > > +
> > > +??? debugfs_create_file("intel-registers", 0400, sdw->fs, sdw,
> > > +??????????????? &intel_reg_fops);
> > > +
> > > +??? sdw_cdns_debugfs_init(&sdw->cdns, sdw->fs);
> > > +}
> >
> > I believe there should be dummy equivalent of _init and _exit if debugfs
> > is not enabled (if these are defined already and I've missed it, please
> > ignore).
>
> I think the direction is just to keep going if there is an error or debufs
> is not enabled.

You should not care either way :)

2019-07-26 18:07:00

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 29/40] soundwire: intel_init: add kernel module parameter to filter out links



On 7/26/19 5:30 AM, Cezary Rojewski wrote:
> On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
>> @@ -83,6 +87,9 @@ static struct sdw_intel_ctx
>>       caps = ioread32(res->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP);
>>       caps &= GENMASK(2, 0);
>> +    dev_dbg(&adev->dev, "SoundWire links: BIOS count %d hardware caps
>> %d\n",
>> +        count, caps);
>> +
>>       /* Check HW supported vs property value and use min of two */
>>       count = min_t(u8, caps, count);
>
> This message does not look like it belongs to current patch - no
> link_mask dependency whatsoever. There have been couple "informative"
> patches in your series, maybe schedule it with them instead (as a
> separate series)?

You're right, this log should be in a different patch. it was added when
I was debugging the DisCo properties a couple of months back and should
be moved. thanks for noting this.

2019-07-26 18:07:52

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 23/40] soundwire: stream: fix disable sequence

Unrelated to this specific patch, but I looked at _sdw_disable_stream()
and I see this there (again, maybe my version is outdated already):

struct sdw_master_runtime *m_rt = NULL;
struct sdw_bus *bus = NULL;

where both those initialisations are redundant. Moreover:

On Thu, Jul 25, 2019 at 06:40:15PM -0500, Pierre-Louis Bossart wrote:
> When we disable the stream and then call hw_free, two bank switches
> will be handled and as a result we re-enable the stream on hw_free.
>
> Make sure the stream is disabled on both banks.
>
> TODO: we need to completely revisit all this and make sure we have a
> mirroring mechanism between current and alternate banks.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/stream.c | 19 ++++++++++++++++++-
> 1 file changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
> index 53f5e790fcd7..75b9ad1fb1a6 100644
> --- a/drivers/soundwire/stream.c
> +++ b/drivers/soundwire/stream.c
> @@ -1637,7 +1637,24 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
> }
> }
>
> - return do_bank_switch(stream);
> + ret = do_bank_switch(stream);
> + if (ret < 0) {
> + dev_err(bus->dev, "Bank switch failed: %d\n", ret);
> + return ret;
> + }
> +
> + /* make sure alternate bank (previous current) is also disabled */
> + list_for_each_entry(m_rt, &stream->master_list, stream_node) {
> + bus = m_rt->bus;

"bus" is only used below, so at least take that line under "if (ret < 0)"
or even just do "dev_err(m_rt->bus->dev,...)" everywhere in this function
and remove the variable altogether...

Thanks
Guennadi

> + /* Disable port(s) */
> + ret = sdw_enable_disable_ports(m_rt, false);
> + if (ret < 0) {
> + dev_err(bus->dev, "Disable port(s) failed: %d\n", ret);
> + return ret;
> + }
> + }
> +
> + return 0;
> }
>
> /**
> --
> 2.20.1
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 18:09:55

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 23/40] soundwire: stream: fix disable sequence


> Unrelated to this specific patch, but I looked at _sdw_disable_stream()
> and I see this there (again, maybe my version is outdated already):
>
> struct sdw_master_runtime *m_rt = NULL;
> struct sdw_bus *bus = NULL;
>
> where both those initialisations are redundant. Moreover:

will look at this, thanks.

>
> On Thu, Jul 25, 2019 at 06:40:15PM -0500, Pierre-Louis Bossart wrote:
>> When we disable the stream and then call hw_free, two bank switches
>> will be handled and as a result we re-enable the stream on hw_free.
>>
>> Make sure the stream is disabled on both banks.
>>
>> TODO: we need to completely revisit all this and make sure we have a
>> mirroring mechanism between current and alternate banks.
>>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/stream.c | 19 ++++++++++++++++++-
>> 1 file changed, 18 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
>> index 53f5e790fcd7..75b9ad1fb1a6 100644
>> --- a/drivers/soundwire/stream.c
>> +++ b/drivers/soundwire/stream.c
>> @@ -1637,7 +1637,24 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
>> }
>> }
>>
>> - return do_bank_switch(stream);
>> + ret = do_bank_switch(stream);
>> + if (ret < 0) {
>> + dev_err(bus->dev, "Bank switch failed: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + /* make sure alternate bank (previous current) is also disabled */
>> + list_for_each_entry(m_rt, &stream->master_list, stream_node) {
>> + bus = m_rt->bus;
>
> "bus" is only used below, so at least take that line under "if (ret < 0)"
> or even just do "dev_err(m_rt->bus->dev,...)" everywhere in this function
> and remove the variable altogether...

will look at this, thanks Guennadi

>
> Thanks
> Guennadi
>
>> + /* Disable port(s) */
>> + ret = sdw_enable_disable_ports(m_rt, false);
>> + if (ret < 0) {
>> + dev_err(bus->dev, "Disable port(s) failed: %d\n", ret);
>> + return ret;

2019-07-26 18:24:44

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 33/40] soundwire: intel: Add basic power management support



On 7/26/19 5:50 AM, Cezary Rojewski wrote:
> On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
>> +static int intel_resume(struct device *dev)
>> +{
>> +    struct sdw_intel *sdw;
>> +    int ret;
>> +
>> +    sdw = dev_get_drvdata(dev);
>> +
>> +    ret = intel_init(sdw);
>> +    if (ret) {
>> +        dev_err(dev, "%s failed: %d", __func__, ret);
>> +        return ret;
>> +    }
>> +
>> +    sdw_cdns_enable_interrupt(&sdw->cdns);
>> +
>> +    return ret;
>> +}
>> +
>> +#endif
>
> Suggestion: the local declaration + initialization via dev_get_drvdata()
> are usually combined.

yes, will do.

>
> Given the upstream declaration of _enable_interrupt, it does return
> error code/ success. Given current flow, if function gets to
> _enable_interrupt call, ret is already set to 0. Returning
> sdw_cds_enable_interrupt() directly would both simplify the definition
> and prevent status loss.

sounds good, will do, thanks!

2019-07-26 18:24:44

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 37/40] soundwire: cadence_master: add hw_reset capability in debugfs

Thanks for the review Greg.

>> +static int cdns_hw_reset(void *data, u64 value)
>> +{
>> + struct sdw_cdns *cdns = data;
>> + int ret;
>> +
>> + if (value != 1)
>> + return 0;
>> +
>> + dev_info(cdns->dev, "starting link hw_reset\n");
>> +
>> + ret = sdw_cdns_exit_reset(cdns);
>> +
>> + dev_info(cdns->dev, "link hw_reset done\n");
>
> Do not be noisy for when things always go right. This looks like
> debuggging code, please remove.

yes, missed this in the cleanup, will remove.

>> +DEFINE_DEBUGFS_ATTRIBUTE(cdns_hw_reset_fops, NULL, cdns_hw_reset, "%llu\n");
>> +
>> /**
>> * sdw_cdns_debugfs_init() - Cadence debugfs init
>> * @cdns: Cadence instance
>> @@ -339,6 +358,9 @@ static const struct file_operations cdns_reg_fops = {
>> void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root)
>> {
>> debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);
>> +
>> + debugfs_create_file_unsafe("cdns-hw-reset", 0200, root, cdns,
>> + &cdns_hw_reset_fops);
>
> Why unsafe?

Dunno. I followed the documentation and my take-away, along with a
number of examples, was to use _unsafe. I really have no idea if this is
correct or not, I can remove this qualifier if that's not needed.

2019-07-26 18:25:16

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 00/40] soundwire: updates for 5.4


>> Comments and feedback welcome!
>
> Hello Pierre,
>
> This patchset is pretty large - I'd suggest dividing next RFC into
> segments: debugfs, info, power-management, basic flow corrections and
> frame shape calculator.

There was an intent to provide a logical progression...

First debugfs, since I believe it was reviewed before, and I wanted
folks like Greg to double-check it without burrying it too deep.

Then all corrections, followed by the allocator.

And last all PM stuff, split by regular suspend/resume and pm_runtime.

The RFC state is precisely to gather feedback, if folks want a different
order that's fine. I just wanted to be transparent and share what we have.

> Some commits have no messages and others lack additional info - tried to
> provide feedback wherever I could, though, especially for the last one,
> it would be vital to post additional info so in-depth feedback can be
> provided.

The lack of commits is a miss, I went from 170 debug/integration patches
to 40 yesterday and my brain was fried.

> Maybe nothing for calculator will come up, maybe something will. In
> general I remember it being an essential part of SDW and one where many
> bugs where found during the initial verification phase.

the frame allocation is a critical piece and it does need to be
hardened. However we can do so in steps. The current setups we have
support 1 Slave per link and a limited amount of bandwidth. The links
themselves don't operate at the max frequency.
Also note that that the streams are 'statically' defined by the
dailinks, and the allocation is not fully dynamic with random
configurations being request. If you fail you fail fast.

Nevertheless I do plan to recheck the allocator with an additional
scripting tool. It'd be very good to e.g. dump the current setup in a
debugfs file and show to users what is happening (or not happening). I
didn't recall you worked on SoundWire and I can use your practical
knowledge to make the code and tools better :-)

>
> Thanks for your contribution and have a good day!

Thanks for reviewing this long series and have a nice week-end.
-Pierre

2019-07-26 19:20:11

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 35/40] soundwire: intel: export helper to exit reset

On Thu, Jul 25, 2019 at 06:40:27PM -0500, Pierre-Louis Bossart wrote:
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 9 +++++++--
> drivers/soundwire/cadence_master.h | 1 +
> drivers/soundwire/intel.c | 4 ++++
> 3 files changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 4a189e487830..f486fe15fb46 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -780,7 +780,11 @@ EXPORT_SYMBOL(sdw_cdns_thread);
> * init routines
> */
>
> -static int do_reset(struct sdw_cdns *cdns)
> +/**
> + * sdw_cdns_exit_reset() - Program reset parameters and start bus operations
> + * @cdns: Cadence instance
> + */
> +int sdw_cdns_exit_reset(struct sdw_cdns *cdns)
> {
> int ret;
>
> @@ -804,6 +808,7 @@ static int do_reset(struct sdw_cdns *cdns)
>
> return ret;
> }
> +EXPORT_SYMBOL(sdw_cdns_exit_reset);
>
> /**
> * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
> @@ -839,7 +844,7 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
>
> cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
>
> - return do_reset(cdns);
> + return 0;
> }
> EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
>
> diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
> index de97bc22acb7..2b551f9226f3 100644
> --- a/drivers/soundwire/cadence_master.h
> +++ b/drivers/soundwire/cadence_master.h
> @@ -161,6 +161,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
> int sdw_cdns_init(struct sdw_cdns *cdns);
> int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
> struct sdw_cdns_stream_config config);
> +int sdw_cdns_exit_reset(struct sdw_cdns *cdns);
> int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
>
> void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index a976480d6f36..9ebe38e4d979 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -1112,6 +1112,8 @@ static int intel_probe(struct platform_device *pdev)
>
> ret = sdw_cdns_enable_interrupt(&sdw->cdns);
>
> + ret = sdw_cdns_exit_reset(&sdw->cdns);

This isn't something, that this patch changes, but if the return value above is
ignored, maybe no need to assign it at all?

Thanks
Guennadi

> +
> /* Register DAIs */
> ret = intel_register_dai(sdw);
> if (ret) {
> @@ -1199,6 +1201,8 @@ static int intel_resume(struct device *dev)
>
> sdw_cdns_enable_interrupt(&sdw->cdns);
>
> + ret = sdw_cdns_exit_reset(&sdw->cdns);
> +
> return ret;
> }
>
> --
> 2.20.1
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 19:20:54

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 38/40] soundwire: cadence_master: make clock stop exit configurable on init

On Thu, Jul 25, 2019 at 06:40:30PM -0500, Pierre-Louis Bossart wrote:
> The use of clock stop is not a requirement, the IP can e.g. be
> completely power gated and not detect any wakes while in s2idle/deep
> sleep.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 15 ++++++++-------
> drivers/soundwire/cadence_master.h | 2 +-
> drivers/soundwire/intel.c | 2 +-
> 3 files changed, 10 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 53278aa2436f..4ab6f70d7705 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -1010,7 +1010,7 @@ static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
> * sdw_cdns_init() - Cadence initialization
> * @cdns: Cadence instance
> */
> -int sdw_cdns_init(struct sdw_cdns *cdns)
> +int sdw_cdns_init(struct sdw_cdns *cdns, bool clock_stop_exit)
> {
> struct sdw_bus *bus = &cdns->bus;
> struct sdw_master_prop *prop = &bus->prop;
> @@ -1018,12 +1018,13 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
> int divider;
> int ret;
>
> - /* Exit clock stop */
> - ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL,
> - CDNS_MCP_CONTROL_CLK_STOP_CLR);
> - if (ret < 0) {
> - dev_err(cdns->dev, "Couldn't exit from clock stop\n");
> - return ret;
> + if (clock_stop_exit) {
> + ret = cdns_clear_bit(cdns, CDNS_MCP_CONTROL,
> + CDNS_MCP_CONTROL_CLK_STOP_CLR);
> + if (ret < 0) {
> + dev_err(cdns->dev, "Couldn't exit from clock stop\n");
> + return ret;
> + }
> }
>
> /* Set clock divider */
> diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
> index 1a0ba36dd78f..091b771b570d 100644
> --- a/drivers/soundwire/cadence_master.h
> +++ b/drivers/soundwire/cadence_master.h
> @@ -158,7 +158,7 @@ extern struct sdw_master_ops sdw_cdns_master_ops;
> irqreturn_t sdw_cdns_irq(int irq, void *dev_id);
> irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
>
> -int sdw_cdns_init(struct sdw_cdns *cdns);
> +int sdw_cdns_init(struct sdw_cdns *cdns, bool clock_stop_exit);
> int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
> struct sdw_cdns_stream_config config);
> int sdw_cdns_exit_reset(struct sdw_cdns *cdns);
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index 1192d5775484..db7bf2912767 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -1043,7 +1043,7 @@ static int intel_init(struct sdw_intel *sdw)
> intel_link_power_up(sdw);
> intel_shim_init(sdw);
>
> - return sdw_cdns_init(&sdw->cdns);
> + return sdw_cdns_init(&sdw->cdns, false);

This is the only caller of this function so far, so, it looks like
the second argument ATM is always "false." I assume you foresee other
uses with "true" in the future, otherwise maybe just fix it to false
in the function?

Thanks
Guennadi

> }
>
> /*
> --
> 2.20.1
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 19:32:24

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 35/40] soundwire: intel: export helper to exit reset


>> @@ -161,6 +161,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
>> int sdw_cdns_init(struct sdw_cdns *cdns);
>> int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
>> struct sdw_cdns_stream_config config);
>> +int sdw_cdns_exit_reset(struct sdw_cdns *cdns);
>> int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
>>
>> void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
>> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
>> index a976480d6f36..9ebe38e4d979 100644
>> --- a/drivers/soundwire/intel.c
>> +++ b/drivers/soundwire/intel.c
>> @@ -1112,6 +1112,8 @@ static int intel_probe(struct platform_device *pdev)
>>
>> ret = sdw_cdns_enable_interrupt(&sdw->cdns);
>>
>> + ret = sdw_cdns_exit_reset(&sdw->cdns);
>
> This isn't something, that this patch changes, but if the return value above is
> ignored, maybe no need to assign it at all?

The return of these two functions was used with in some logs at some
point but they obviously vanished.
I'll re-check if we care about the status, could be that it never fails
Thanks!


>> +
>> /* Register DAIs */
>> ret = intel_register_dai(sdw);
>> if (ret) {
>> @@ -1199,6 +1201,8 @@ static int intel_resume(struct device *dev)
>>
>> sdw_cdns_enable_interrupt(&sdw->cdns);
>>
>> + ret = sdw_cdns_exit_reset(&sdw->cdns);
>> +
>> return ret;

2019-07-26 19:33:54

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 38/40] soundwire: cadence_master: make clock stop exit configurable on init


>> -int sdw_cdns_init(struct sdw_cdns *cdns);
>> +int sdw_cdns_init(struct sdw_cdns *cdns, bool clock_stop_exit);
>> int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
>> struct sdw_cdns_stream_config config);
>> int sdw_cdns_exit_reset(struct sdw_cdns *cdns);
>> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
>> index 1192d5775484..db7bf2912767 100644
>> --- a/drivers/soundwire/intel.c
>> +++ b/drivers/soundwire/intel.c
>> @@ -1043,7 +1043,7 @@ static int intel_init(struct sdw_intel *sdw)
>> intel_link_power_up(sdw);
>> intel_shim_init(sdw);
>>
>> - return sdw_cdns_init(&sdw->cdns);
>> + return sdw_cdns_init(&sdw->cdns, false);
>
> This is the only caller of this function so far, so, it looks like
> the second argument ATM is always "false." I assume you foresee other
> uses with "true" in the future, otherwise maybe just fix it to false
> in the function?

Since we are at RFC level things are not set in stone, it's not fully
clear if this test is required or not. I added it since Rander reported
an error on one of the target platforms that I didn't see personally.
We'll double-check if it's needed. And if indeed it's needed, yes it'll
be set to true when we add clock stop.

2019-07-26 19:36:19

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 27/40] soundwire: Add Intel resource management algorithm

Thanks Guennadi for looking at this code, it's hard to review and figure
things out...
I replied to each, even trivial ones, to have a trace of all the issues.

>> +static void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt,
>> + struct sdw_transport_data *t_data)
>> +{
>> + struct sdw_slave_runtime *s_rt = NULL;
>
> Superfluous initialisation.

ok

>
>> + struct sdw_port_runtime *p_rt;
>> + int port_bo, sample_int;
>> + unsigned int rate, bps, ch = 0;
>
> ditto for ch

ok

>> +
>> + port_bo = t_data->block_offset;
>> +
>> + list_for_each_entry(s_rt, &m_rt->slave_rt_list, m_rt_node) {
>> + rate = m_rt->stream->params.rate;
>> + bps = m_rt->stream->params.bps;
>> + sample_int = (m_rt->bus->params.curr_dr_freq / rate);
>> +
>> + list_for_each_entry(p_rt, &s_rt->port_list, port_node) {
>> + ch = sdw_ch_mask_to_ch(p_rt->ch_mask);
>> +
>> + sdw_fill_xport_params(&p_rt->transport_params,
>> + p_rt->num, true,
>> + SDW_BLK_GRP_CNT_1,
>> + sample_int, port_bo, port_bo >> 8,
>> + t_data->hstart,
>> + t_data->hstop,
>
> I think the above two lines could fit in one

likely yes.

>
>> + (SDW_BLK_GRP_CNT_1 * ch), 0x0);
>
> superfluous parentheses

yep


>> +static void sdw_compute_master_ports(struct sdw_master_runtime *m_rt,
>> + struct sdw_group_params *params,
>> + int port_bo, int hstop)
>> +{
>> + struct sdw_transport_data t_data = {0};
>> + struct sdw_port_runtime *p_rt;
>> + struct sdw_bus *bus = m_rt->bus;
>> + int sample_int, hstart = 0;
>
> superfluous initialisation

yes

>
>> + unsigned int rate, bps, ch, no_ch;
>> +
>> + rate = m_rt->stream->params.rate;
>> + bps = m_rt->stream->params.bps;
>> + ch = m_rt->ch_count;
>> + sample_int = (bus->params.curr_dr_freq / rate);
>
> superfluous parentheses

yes

>> +
>> + if (rate != params->rate)
>> + return;
>> +
>> + t_data.hstop = hstop;
>> + hstart = hstop - params->hwidth + 1;
>> + t_data.hstart = hstart;
>> +
>> + list_for_each_entry(p_rt, &m_rt->port_list, port_node) {
>> + no_ch = sdw_ch_mask_to_ch(p_rt->ch_mask);
>> +
>> + sdw_fill_xport_params(&p_rt->transport_params, p_rt->num,
>> + true, SDW_BLK_GRP_CNT_1, sample_int,
>> + port_bo, port_bo >> 8, hstart, hstop,
>> + (SDW_BLK_GRP_CNT_1 * no_ch), 0x0);
>
> superfluous parentheses

yes

>
>> +
>> + sdw_fill_port_params(&p_rt->port_params,
>> + p_rt->num, bps,
>> + SDW_PORT_FLOW_MODE_ISOCH,
>> + SDW_PORT_DATA_MODE_NORMAL);
>> +
>> + /* Check for first entry */
>> + if (!(p_rt == list_first_entry(&m_rt->port_list,
>> + struct sdw_port_runtime,
>> + port_node))) {
>
> you wanted to write "if (p_rt != ...)"

bad code indeed, thanks for spotting this. I need to double-check this
one, now I don't trust the ==
it could also be that it was meant to be a NULL check on the first entry.

>
>> + port_bo += bps * ch;
>> + continue;
>> + }
>> +
>> + t_data.hstart = hstart;
>> + t_data.hstop = hstop;
>
> You already set these two above

need to check this as well.

>
>> + t_data.block_offset = port_bo;
>> + t_data.sub_block_offset = 0;
>> + port_bo += bps * ch;
>> + }
>> +
>> + sdw_compute_slave_ports(m_rt, &t_data);
>> +}
>> +
>> +static void _sdw_compute_port_params(struct sdw_bus *bus,
>> + struct sdw_group_params *params, int count)
>> +{
>> + struct sdw_master_runtime *m_rt = NULL;
>
> superfluous initialisation

yes

>
>> + int hstop = bus->params.col - 1;
>> + int block_offset, port_bo, i;
>> +
>> + /* Run loop for all groups to compute transport parameters */
>> + for (i = 0; i < count; i++) {
>> + port_bo = 1;
>> + block_offset = 1;
>> +
>> + list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
>> + sdw_compute_master_ports(m_rt, &params[i],
>> + port_bo, hstop);
>> +
>> + block_offset += m_rt->ch_count *
>> + m_rt->stream->params.bps;
>> + port_bo = block_offset;
>> + }
>> +
>> + hstop = hstop - params[i].hwidth;
>
> hstop -= ...

yes

>
>> + }
>> +}
>> +
>> +static int sdw_compute_group_params(struct sdw_bus *bus,
>> + struct sdw_group_params *params,
>> + int *rates, int count)
>> +{
>> + struct sdw_master_runtime *m_rt = NULL;
>
> ditto

yes

>> + int sel_col = bus->params.col;
>> + unsigned int rate, bps, ch;
>> + int i, column_needed = 0;
>> +
>> + /* Calculate bandwidth per group */
>> + for (i = 0; i < count; i++) {
>> + params[i].rate = rates[i];
>> + params[i].full_bw = bus->params.curr_dr_freq / params[i].rate;
>> + }
>> +
>> + list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
>> + rate = m_rt->stream->params.rate;
>> + bps = m_rt->stream->params.bps;
>> + ch = m_rt->ch_count;
>> +
>> + for (i = 0; i < count; i++) {
>> + if (rate == params[i].rate)
>> + params[i].payload_bw += bps * ch;
>
> I don't know about the algorithm, rates can repeat, right? So you cannot break
> out of the loop here once you found one match?

This code looks wrong. Need to get an intravenous caffeine injection.

>
>> + }
>> + }
>> +
>> + for (i = 0; i < count; i++) {
>> + params[i].hwidth = (sel_col *
>> + params[i].payload_bw + params[i].full_bw - 1) /
>> + params[i].full_bw;
>> +
>> + column_needed += params[i].hwidth;
>> + }
>> +
>> + if (column_needed > sel_col - 1)
>> + return -EINVAL;
>> +
>> + return 0;
>> +}
>> +
>> +static int sdw_add_element_group_count(struct sdw_group *group,
>> + unsigned int rate)
>> +{
>> + int num = group->count;
>> + int i;
>> +
>> + for (i = 0; i <= num; i++) {
>> + if (rate == group->rates[i])
>
> Are you sure this is correct? You actually check count + 1 rates - from 0
> to count inclusively. I think this isn't what you wanted to do, so my
> proposal below only checks count rates.

I'll have to double check. There's already the warning on krealloc that
looks suspicious as well.

>
>> + break;
>> +
>> + if (i != num)
>> + continue;
>> +
>> + if (group->count >= group->max_size) {
>> + group->max_size += 1;
>> + group->rates = krealloc(group->rates,
>> + (sizeof(int) * group->max_size),
>> + GFP_KERNEL);
>> + if (!group->rates)
>> + return -ENOMEM;
>> + }
>> +
>> + group->rates[group->count++] = rate;
>> + }
>
> How about this:
>
> for (i = 0; i < num; i++)
> if (rate == group->rates[i])
> return 0;
>
> if (group->count >= group->max_size) {
> group->max_size += 1;
> group->rates = krealloc(group->rates,
> (sizeof(int) * group->max_size),
> GFP_KERNEL);
> if (!group->rates)
> return -ENOMEM;
> }
>
> group->rates[group->count++] = rate;
>
> return 0;

will check offline and see.

>> +
>> + return 0;
>> +}
>> +
>> +static int sdw_get_group_count(struct sdw_bus *bus,
>> + struct sdw_group *group)
>> +{
>> + struct sdw_master_runtime *m_rt;
>> + unsigned int rate;
>> + int ret = 0;
>> +
>> + group->count = 0;
>> + group->max_size = SDW_STRM_RATE_GROUPING;
>> + group->rates = kcalloc(group->max_size, sizeof(int), GFP_KERNEL);
>> + if (!group->rates)
>> + return -ENOMEM;
>> +
>> + list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
>> + rate = m_rt->stream->params.rate;
>> + if (m_rt == list_first_entry(&bus->m_rt_list,
>> + struct sdw_master_runtime,
>> + bus_node)) {
>> + group->rates[group->count++] = rate;
>> +
>> + } else {
>> + ret = sdw_add_element_group_count(group, rate);
>> + if (ret < 0)
>
> Actually it looks like you should free rates here? I see that not doing this
> makes the caller function below easier, but I'd say this is more error-
> prone... Up to you but I'd go the "safe" way - if it fails, it frees itself,
> if it succeeds - it's freed elsewhere.

good catch, will look into this.

>
>> + return ret;
>> + }
>> + }
>> +
>> + return ret;
>
> I think this will always return 0 here, so you don't need the "ret"
> variable in the function scope, you only need it in the "else"
> scope above.

will check. In general I avoid per-scope declarations.

>> +}
>> +
>> +/**
>> + * sdw_compute_port_params: Compute transport and port parameters
>> + *
>> + * @bus: SDW Bus instance
>> + */
>> +static int sdw_compute_port_params(struct sdw_bus *bus)
>> +{
>> + struct sdw_group_params *params = NULL;
>> + struct sdw_group group;
>> + int ret;
>> +
>> + ret = sdw_get_group_count(bus, &group);
>> + if (ret < 0)
>> + goto out;
>> +
>> + if (group.count == 0)
>> + goto out;
>> +
>> + params = kcalloc(group.count, sizeof(*params), GFP_KERNEL);
>> + if (!params) {
>> + ret = -ENOMEM;
>> + goto out;
>> + }
>> +
>> + /* Compute transport parameters for grouped streams */
>> + ret = sdw_compute_group_params(bus, params,
>> + &group.rates[0], group.count);
>> + if (ret < 0)
>> + goto out;
>> +
>> + _sdw_compute_port_params(bus, params, group.count);
>> +
>> +out:
>> + kfree(params);
>> + kfree(group.rates);
>
> Depending whether or not you change the code above, this might change
> too.

will check

>> +static int sdw_compute_bus_params(struct sdw_bus *bus)
>> +{
>> + unsigned int max_dr_freq, curr_dr_freq = 0;
>> + struct sdw_master_prop *mstr_prop = NULL;
>
> superfluous initialisation

yes

>> + int i, clk_values, ret;
>> + bool is_gear = false;
>> + u32 *clk_buf;
>> +
>> + mstr_prop = &bus->prop;
>> + if (!mstr_prop)
>
> this is impossible, it's an address of bus->prop...

Gah, yes.

>> + return -EINVAL;
>> +
>> + if (mstr_prop->num_clk_gears) {
>> + clk_values = mstr_prop->num_clk_gears;
>> + clk_buf = mstr_prop->clk_gears;
>> + is_gear = true;
>> + } else if (mstr_prop->num_clk_freq) {
>> + clk_values = mstr_prop->num_clk_freq;
>> + clk_buf = mstr_prop->clk_freq;
>> + } else {
>> + clk_values = 1;
>> + clk_buf = NULL;
>> + }
>> +
>> + max_dr_freq = mstr_prop->max_clk_freq * SDW_DOUBLE_RATE_FACTOR;
>> +
>> + for (i = 0; i < clk_values; i++) {
>> + if (!clk_buf)
>> + curr_dr_freq = max_dr_freq;
>> + else
>> + curr_dr_freq = (is_gear) ?
>
> superfluous parentheses
>
>> + (max_dr_freq >> clk_buf[i]) :
>
> ditto

yes and yes
>
>> + clk_buf[i] * SDW_DOUBLE_RATE_FACTOR;
>> +
>> + if (curr_dr_freq <= bus->params.bandwidth)
>> + continue;
>> +
>> + break;
>
> I think this is raw code, you'd actually want to write this as
>
> if (curr_dr_freq > bus->params.bandwidth)
> break;

I saw this before my Summer break and forgot about it. yes it needs to
be fixed.

>>
>> bus->debugfs = sdw_bus_debugfs_init(bus);
>>
>> + if (!bus->compute_params)
>> + bus->compute_params = &sdw_compute_params;
>
> I think it is more usual to not use "&" with functions, but it's valid too

yes, will fix


>> +/* Retrieve and return channel count from channel mask */
>> +static inline int sdw_ch_mask_to_ch(int ch_mask)
>> +{
>> + int c = 0;
>
> superfluous initialisation

yes

>
>> +
>> + for (c = 0; ch_mask; ch_mask >>= 1)
>> + c += ch_mask & 1;
>
> isn't there a built-in or something to count set bits... You could use ffs() to
> at least not loop 31 times for 0x80000000

will check

2019-07-26 19:38:34

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled

This thread became unreadable with interleaved top-posting, allow me
restate the options and ask PM folks what they think

On 7/25/19 6:40 PM, Pierre-Louis Bossart wrote:
> Not all platforms support runtime_pm for now, let's use runtime_pm
> only when enabled.
>
> Suggested-by: Srinivas Kandagatla <[email protected]>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/bus.c | 25 ++++++++++++++++---------
> 1 file changed, 16 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
> index 5ad4109dc72f..0a45dc5713df 100644
> --- a/drivers/soundwire/bus.c
> +++ b/drivers/soundwire/bus.c
> @@ -332,12 +332,16 @@ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
> if (ret < 0)
> return ret;
>
> - ret = pm_runtime_get_sync(slave->bus->dev);
> - if (ret < 0)
> - return ret;
> + if (pm_runtime_enabled(slave->bus->dev)) {
> + ret = pm_runtime_get_sync(slave->bus->dev);
> + if (ret < 0)
> + return ret;
> + }
>
> ret = sdw_transfer(slave->bus, &msg);
> - pm_runtime_put(slave->bus->dev);
> +
> + if (pm_runtime_enabled(slave->bus->dev))
> + pm_runtime_put(slave->bus->dev);

This is option1: we explicitly test if pm_runtime is enabled before
calling _get_sync() and _put()

option2 (suggested by Jan Kotas): catch the -EACCESS error code

ret = pm_runtime_get_sync(slave->bus->dev);
- if (ret < 0)
+ if (ret < 0 && ret != -EACCES)
return ret;

option3: ignore the return value as done in quite a few drivers

Are there any other options? I am personally surprised this is not
handled in the pm_runtime core, not sure why users need to test for this?

Thanks
Pierre

2019-07-26 21:46:45

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 37/40] soundwire: cadence_master: add hw_reset capability in debugfs

On Thu, Jul 25, 2019 at 06:40:29PM -0500, Pierre-Louis Bossart wrote:
> This is to kick devices into reset and see what software does
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index fa7230b0f200..53278aa2436f 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -331,6 +331,25 @@ static const struct file_operations cdns_reg_fops = {
> .llseek = default_llseek,
> };
>
> +static int cdns_hw_reset(void *data, u64 value)
> +{
> + struct sdw_cdns *cdns = data;
> + int ret;
> +
> + if (value != 1)
> + return 0;
> +
> + dev_info(cdns->dev, "starting link hw_reset\n");
> +
> + ret = sdw_cdns_exit_reset(cdns);
> +
> + dev_info(cdns->dev, "link hw_reset done\n");

Both really should be dev_info()? Maybe at least one of them can be dev_dbg()?

Thanks
Guennadi

> +
> + return ret;
> +}
> +
> +DEFINE_DEBUGFS_ATTRIBUTE(cdns_hw_reset_fops, NULL, cdns_hw_reset, "%llu\n");
> +
> /**
> * sdw_cdns_debugfs_init() - Cadence debugfs init
> * @cdns: Cadence instance
> @@ -339,6 +358,9 @@ static const struct file_operations cdns_reg_fops = {
> void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root)
> {
> debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);
> +
> + debugfs_create_file_unsafe("cdns-hw-reset", 0200, root, cdns,
> + &cdns_hw_reset_fops);
> }
> EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init);
>
> --
> 2.20.1
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 21:46:45

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 36/40] soundwire: intel: disable interrupts on suspend

On Thu, Jul 25, 2019 at 06:40:28PM -0500, Pierre-Louis Bossart wrote:
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 42 +++++++++++++++++-------------
> drivers/soundwire/cadence_master.h | 2 +-
> drivers/soundwire/intel.c | 6 +++--
> 3 files changed, 29 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index f486fe15fb46..fa7230b0f200 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -814,33 +814,39 @@ EXPORT_SYMBOL(sdw_cdns_exit_reset);
> * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
> * @cdns: Cadence instance
> */
> -int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
> +int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state)
> {
> u32 mask;
>
> - cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0,
> - CDNS_MCP_SLAVE_INTMASK0_MASK);
> - cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1,
> - CDNS_MCP_SLAVE_INTMASK1_MASK);
> + if (state) {
> + cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0,
> + CDNS_MCP_SLAVE_INTMASK0_MASK);
> + cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1,
> + CDNS_MCP_SLAVE_INTMASK1_MASK);
>
> - /* enable detection of slave state changes */
> - mask = CDNS_MCP_INT_SLAVE_RSVD | CDNS_MCP_INT_SLAVE_ALERT |
> - CDNS_MCP_INT_SLAVE_ATTACH | CDNS_MCP_INT_SLAVE_NATTACH;
> + /* enable detection of slave state changes */
> + mask = CDNS_MCP_INT_SLAVE_RSVD | CDNS_MCP_INT_SLAVE_ALERT |
> + CDNS_MCP_INT_SLAVE_ATTACH | CDNS_MCP_INT_SLAVE_NATTACH;
>
> - /* enable detection of bus issues */
> - mask |= CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
> - CDNS_MCP_INT_PARITY;
> + /* enable detection of bus issues */
> + mask |= CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
> + CDNS_MCP_INT_PARITY;
>
> - /* no detection of port interrupts for now */
> + /* no detection of port interrupts for now */
>
> - /* enable detection of RX fifo level */
> - mask |= CDNS_MCP_INT_RX_WL;
> + /* enable detection of RX fifo level */
> + mask |= CDNS_MCP_INT_RX_WL;
>
> - /* now enable all of the above */
> - mask |= CDNS_MCP_INT_IRQ;
> + /* now enable all of the above */
> + mask |= CDNS_MCP_INT_IRQ;
>
> - if (interrupt_mask) /* parameter override */
> - mask = interrupt_mask;
> + if (interrupt_mask) /* parameter override */
> + mask = interrupt_mask;
> + } else {
> + cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK0, 0);
> + cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1, 0);
> + mask = 0;
> + }

Looks like this should be two functions? Especially since "state" is always a constant
when it is called. If there is still a lot of common code below, maybe make it a helper
function.

Thanks
Guennadi

>
> cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
>
> diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
> index 2b551f9226f3..1a0ba36dd78f 100644
> --- a/drivers/soundwire/cadence_master.h
> +++ b/drivers/soundwire/cadence_master.h
> @@ -162,7 +162,7 @@ int sdw_cdns_init(struct sdw_cdns *cdns);
> int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
> struct sdw_cdns_stream_config config);
> int sdw_cdns_exit_reset(struct sdw_cdns *cdns);
> -int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
> +int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns, bool state);
>
> void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
>
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index 9ebe38e4d979..1192d5775484 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -1110,7 +1110,7 @@ static int intel_probe(struct platform_device *pdev)
> goto err_init;
> }
>
> - ret = sdw_cdns_enable_interrupt(&sdw->cdns);
> + ret = sdw_cdns_enable_interrupt(&sdw->cdns, true);
>
> ret = sdw_cdns_exit_reset(&sdw->cdns);
>
> @@ -1169,6 +1169,8 @@ static int intel_suspend(struct device *dev)
> return 0;
> }
>
> + sdw_cdns_enable_interrupt(&sdw->cdns, false);
> +
> ret = intel_link_power_down(sdw);
> if (ret) {
> dev_err(dev, "Link power down failed: %d", ret);
> @@ -1199,7 +1201,7 @@ static int intel_resume(struct device *dev)
> return ret;
> }
>
> - sdw_cdns_enable_interrupt(&sdw->cdns);
> + sdw_cdns_enable_interrupt(&sdw->cdns, true);
>
> ret = sdw_cdns_exit_reset(&sdw->cdns);
>
> --
> 2.20.1
>
> _______________________________________________
> Alsa-devel mailing list
> [email protected]
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

2019-07-26 22:31:14

by Guennadi Liakhovetski

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled

On Fri, Jul 26, 2019 at 01:08:57PM -0500, Pierre-Louis Bossart wrote:
> This thread became unreadable with interleaved top-posting, allow me restate
> the options and ask PM folks what they think
>
> On 7/25/19 6:40 PM, Pierre-Louis Bossart wrote:
> > Not all platforms support runtime_pm for now, let's use runtime_pm
> > only when enabled.
> >
> > Suggested-by: Srinivas Kandagatla <[email protected]>
> > Signed-off-by: Pierre-Louis Bossart <[email protected]>
> > ---
> > drivers/soundwire/bus.c | 25 ++++++++++++++++---------
> > 1 file changed, 16 insertions(+), 9 deletions(-)
> >
> > diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
> > index 5ad4109dc72f..0a45dc5713df 100644
> > --- a/drivers/soundwire/bus.c
> > +++ b/drivers/soundwire/bus.c
> > @@ -332,12 +332,16 @@ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
> > if (ret < 0)
> > return ret;
> > - ret = pm_runtime_get_sync(slave->bus->dev);
> > - if (ret < 0)
> > - return ret;
> > + if (pm_runtime_enabled(slave->bus->dev)) {
> > + ret = pm_runtime_get_sync(slave->bus->dev);
> > + if (ret < 0)
> > + return ret;
> > + }
> > ret = sdw_transfer(slave->bus, &msg);
> > - pm_runtime_put(slave->bus->dev);
> > +
> > + if (pm_runtime_enabled(slave->bus->dev))
> > + pm_runtime_put(slave->bus->dev);
>
> This is option1: we explicitly test if pm_runtime is enabled before calling
> _get_sync() and _put()
>
> option2 (suggested by Jan Kotas): catch the -EACCESS error code
>
> ret = pm_runtime_get_sync(slave->bus->dev);
> - if (ret < 0)
> + if (ret < 0 && ret != -EACCES)
> return ret;
>
> option3: ignore the return value as done in quite a few drivers
>
> Are there any other options? I am personally surprised this is not handled
> in the pm_runtime core, not sure why users need to test for this?

option 4: fix this in runtime PM :-) This seems like the best option to me,
but probably not the easiest one. Otherwise I'd go with (2), I think, since
that's also the official purpose of the -EACCESS return code:

https://lists.linuxfoundation.org/pipermail/linux-pm/2011-June/031930.html

Thanks
Guennadi

2019-07-26 22:46:49

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled

On Fri, Jul 26, 2019 at 01:08:57PM -0500, Pierre-Louis Bossart wrote:
> This thread became unreadable with interleaved top-posting, allow me restate
> the options and ask PM folks what they think
>
> On 7/25/19 6:40 PM, Pierre-Louis Bossart wrote:
> > Not all platforms support runtime_pm for now, let's use runtime_pm
> > only when enabled.

Just a side note below...

> > - ret = pm_runtime_get_sync(slave->bus->dev);
> > - if (ret < 0)

Here...

> > - return ret;
> > + if (pm_runtime_enabled(slave->bus->dev)) {
> > + ret = pm_runtime_get_sync(slave->bus->dev);
> > + if (ret < 0)

...and thus here...

> > + return ret;
> > + }
> > ret = sdw_transfer(slave->bus, &msg);
> > - pm_runtime_put(slave->bus->dev);
> > +
> > + if (pm_runtime_enabled(slave->bus->dev))
> > + pm_runtime_put(slave->bus->dev);
>
> This is option1: we explicitly test if pm_runtime is enabled before calling
> _get_sync() and _put()
>
> option2 (suggested by Jan Kotas): catch the -EACCESS error code
>
> ret = pm_runtime_get_sync(slave->bus->dev);
> - if (ret < 0)
> + if (ret < 0 && ret != -EACCES)

...and here, the pm_runtime_put_noidle() call is missed.

> return ret;
>
> option3: ignore the return value as done in quite a few drivers
>
> Are there any other options? I am personally surprised this is not handled
> in the pm_runtime core, not sure why users need to test for this?

--
With Best Regards,
Andy Shevchenko



2019-07-30 03:36:04

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled



On 7/26/19 2:08 PM, Andy Shevchenko wrote:
> On Fri, Jul 26, 2019 at 01:08:57PM -0500, Pierre-Louis Bossart wrote:
>> This thread became unreadable with interleaved top-posting, allow me restate
>> the options and ask PM folks what they think
>>
>> On 7/25/19 6:40 PM, Pierre-Louis Bossart wrote:
>>> Not all platforms support runtime_pm for now, let's use runtime_pm
>>> only when enabled.
>
> Just a side note below...
>
>>> - ret = pm_runtime_get_sync(slave->bus->dev);
>>> - if (ret < 0)
>
> Here...
>
>>> - return ret;
>>> + if (pm_runtime_enabled(slave->bus->dev)) {
>>> + ret = pm_runtime_get_sync(slave->bus->dev);
>>> + if (ret < 0)
>
> ...and thus here...
>
>>> + return ret;
>>> + }
>>> ret = sdw_transfer(slave->bus, &msg);
>>> - pm_runtime_put(slave->bus->dev);
>>> +
>>> + if (pm_runtime_enabled(slave->bus->dev))
>>> + pm_runtime_put(slave->bus->dev);
>>
>> This is option1: we explicitly test if pm_runtime is enabled before calling
>> _get_sync() and _put()
>>
>> option2 (suggested by Jan Kotas): catch the -EACCESS error code
>>
>> ret = pm_runtime_get_sync(slave->bus->dev);
>> - if (ret < 0)
>> + if (ret < 0 && ret != -EACCES)
>
> ...and here, the pm_runtime_put_noidle() call is missed.

yes but in the example you provided, they actually do more work than
just decrement the device usage counter:

static int
radeonfb_open(struct fb_info *info, int user)
{
struct radeon_fbdev *rfbdev = info->par;
struct radeon_device *rdev = rfbdev->rdev;
int ret = pm_runtime_get_sync(rdev->ddev->dev);
if (ret < 0 && ret != -EACCES) {
pm_runtime_mark_last_busy(rdev->ddev->dev);
pm_runtime_put_autosuspend(rdev->ddev->dev);
return ret;
}
return 0;
}

unless I am missing something pm_runtime_put_noidle() and
_put_autosuspend() are not equivalent, are they?

2019-07-30 12:12:52

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled

On Mon, Jul 29, 2019 at 05:07:39PM -0500, Pierre-Louis Bossart wrote:
> On 7/26/19 2:08 PM, Andy Shevchenko wrote:
> > On Fri, Jul 26, 2019 at 01:08:57PM -0500, Pierre-Louis Bossart wrote:

> > > - if (ret < 0)
> > > + if (ret < 0 && ret != -EACCES)
> >
> > ...and here, the pm_runtime_put_noidle() call is missed.
>
> yes but in the example you provided, they actually do more work than just
> decrement the device usage counter:

In their case they would like to do that. You decide what is appropriate call
in your case.

My point is, that reference counter in case of error handling should be
returned back to its value.

--
With Best Regards,
Andy Shevchenko


2019-07-30 12:58:40

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled



On 7/30/19 6:21 AM, Andy Shevchenko wrote:
> On Mon, Jul 29, 2019 at 05:07:39PM -0500, Pierre-Louis Bossart wrote:
>> On 7/26/19 2:08 PM, Andy Shevchenko wrote:
>>> On Fri, Jul 26, 2019 at 01:08:57PM -0500, Pierre-Louis Bossart wrote:
>
>>>> - if (ret < 0)
>>>> + if (ret < 0 && ret != -EACCES)
>>>
>>> ...and here, the pm_runtime_put_noidle() call is missed.
>>
>> yes but in the example you provided, they actually do more work than just
>> decrement the device usage counter:
>
> In their case they would like to do that. You decide what is appropriate call
> in your case.
>
> My point is, that reference counter in case of error handling should be
> returned back to its value.

Agree on the reference count.
I am however not clear on the next step and 'what is appropriate'.

If pm_runtime_get_sync() failed, then technically the device was not
resumed so marking it as last_busy+autosuspend, or using a plain vanilla
put() will not result in any action. I must be missing something here.

2019-07-30 16:45:41

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled

On Tue, Jul 30, 2019 at 07:57:46AM -0500, Pierre-Louis Bossart wrote:
> On 7/30/19 6:21 AM, Andy Shevchenko wrote:
> > On Mon, Jul 29, 2019 at 05:07:39PM -0500, Pierre-Louis Bossart wrote:
> > > On 7/26/19 2:08 PM, Andy Shevchenko wrote:
> > > > On Fri, Jul 26, 2019 at 01:08:57PM -0500, Pierre-Louis Bossart wrote:
> >
> > > > > - if (ret < 0)
> > > > > + if (ret < 0 && ret != -EACCES)
> > > >
> > > > ...and here, the pm_runtime_put_noidle() call is missed.
> > >
> > > yes but in the example you provided, they actually do more work than just
> > > decrement the device usage counter:
> >
> > In their case they would like to do that. You decide what is appropriate call
> > in your case.
> >
> > My point is, that reference counter in case of error handling should be
> > returned back to its value.
>
> Agree on the reference count.
> I am however not clear on the next step and 'what is appropriate'.
>
> If pm_runtime_get_sync() failed, then technically the device was not resumed

Not so straight. It depends on reference count. It might be true (most cases
I think), or not true, if device had been resumed previously by other call.

> so marking it as last_busy+autosuspend, or using a plain vanilla put() will
> not result in any action. I must be missing something here.

put_noidle(). Because if it failed on the first call and was resumed, put()
will try to shut it down (since reference count goes to no-user base).

--
With Best Regards,
Andy Shevchenko


2019-08-02 14:10:06

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 03/40] soundwire: cadence_master: align debugfs to 8 digits

On 25-07-19, 18:39, Pierre-Louis Bossart wrote:
> SQUASHME

Git trick!

commit this using:
git fixup <sha1>

where sha1 is commit where you want this to be squashed into!

then below will suuash them for you!

git rebase -i --autosquash



>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 91e8bacb83e3..9f611a1fff0a 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -234,7 +234,7 @@ static ssize_t cdns_sprintf(struct sdw_cdns *cdns,
> char *buf, size_t pos, unsigned int reg)
> {
> return scnprintf(buf + pos, RD_BUF - pos,
> - "%4x\t%4x\n", reg, cdns_readl(cdns, reg));
> + "%4x\t%8x\n", reg, cdns_readl(cdns, reg));
> }
>
> static ssize_t cdns_reg_read(struct file *file, char __user *user_buf,
> --
> 2.20.1

--
~Vinod

2019-08-02 14:11:20

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 05/40] soundwire: intel: move interrupt enable after interrupt handler registration

On 25-07-19, 18:39, Pierre-Louis Bossart wrote:
> Not sure why the existing code would enable interrupts without the
> ability to deal with them.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/intel.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index aeadc341c0a3..68832e613b1e 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -981,8 +981,6 @@ static int intel_probe(struct platform_device *pdev)
> if (ret)
> goto err_init;
>
> - ret = sdw_cdns_enable_interrupt(&sdw->cdns);
> -
> /* Read the PDI config and initialize cadence PDI */
> intel_pdi_init(sdw, &config);
> ret = sdw_cdns_pdi_init(&sdw->cdns, config);
> @@ -1000,6 +998,8 @@ static int intel_probe(struct platform_device *pdev)
> goto err_init;
> }
>
> + ret = sdw_cdns_enable_interrupt(&sdw->cdns);

we should also handle the return

--
~Vinod

2019-08-02 22:07:04

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 06/40] soundwire: intel: prevent possible dereference in hw_params

On 25-07-19, 18:39, Pierre-Louis Bossart wrote:
> This should not happen in production systems but we should test for
> all callback arguments before invoking the config_stream callback.

so you are saying callback arg is mandatory, if so please document that
assumption

> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/intel.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index 68832e613b1e..497879dd9c0d 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -509,7 +509,7 @@ static int intel_config_stream(struct sdw_intel *sdw,
> struct snd_soc_dai *dai,
> struct snd_pcm_hw_params *hw_params, int link_id)
> {
> - if (sdw->res->ops && sdw->res->ops->config_stream)
> + if (sdw->res->ops && sdw->res->ops->config_stream && sdw->res->arg)
> return sdw->res->ops->config_stream(sdw->res->arg,
> substream, dai, hw_params, link_id);
>
> --
> 2.20.1

--
~Vinod

2019-08-02 22:07:45

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 07/40] soundwire: intel: fix channel number reported by hardware

On 25-07-19, 18:39, Pierre-Louis Bossart wrote:
> PDI2 reports an invalid count, force the correct hardware-supported
> value
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/intel.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index 497879dd9c0d..51990b192dc0 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -401,6 +401,15 @@ intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm)
>
> if (pcm) {
> count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num));
> +
> + /*
> + * TODO: pdi number 2 reports channel count as 1 even though
> + * it supports 8 channel. Performing hardcoding for pdi
> + * number 2.
> + */
> + if (pdi_num == 2)
> + count = 7;

Is that true for all Intel controllers or some generations. Would it not
be better to put this under some flag which is set on platform basis?

> +
> } else {
> count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
> count = ((count & SDW_SHIM_PDMSCAP_CPSS) >>
> --
> 2.20.1

--
~Vinod

2019-08-02 22:09:13

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 09/40] soundwire: cadence_master: fix usage of CONFIG_UPDATE

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:

> int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
> {
> - int ret;
> -
> _cdns_enable_interrupt(cdns);
> - ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
> - CDNS_MCP_CONFIG_UPDATE_BIT);
> - if (ret < 0)
> - dev_err(cdns->dev, "Config update timedout\n");

I was expecting cdns_update_config() to be invoked here??

>
> - return ret;
> + return 0;

It would be better if we return a value here a not success always

> @@ -943,7 +953,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
>
> cdns_writel(cdns, CDNS_MCP_CONFIG, val);
>
> - return 0;
> + /* commit changes */
> + ret = cdns_update_config(cdns);
> +
> + return ret;

return cdns_update_config()

--
~Vinod

2019-08-02 22:11:06

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 11/40] soundwire: cadence_master: simplify bus clash interrupt clear

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
> The bus clash interrupts are generated when the status is one, and
> also cleared by writing a one. It's overkill/useless to use an OR when
> the bit is already set.

IIRC we were supposed to have different variable and that was the reason
for setting, yes should be removed.

I have applied this one as well

--
~Vinod

2019-08-02 22:13:39

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 12/40] soundwire: cadence_master: revisit interrupt settings

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
> Adding missing interrupt masks (parity, etc) and missing checks.
> Clarify which masks are for which usage.
>
> Signed-off-by: Bard Liao <[email protected]>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 25 ++++++++++++++++++++++---
> 1 file changed, 22 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index bdc3ed844829..0f3b9c160b01 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -76,9 +76,12 @@
> #define CDNS_MCP_INT_DPINT BIT(11)
> #define CDNS_MCP_INT_CTRL_CLASH BIT(10)
> #define CDNS_MCP_INT_DATA_CLASH BIT(9)
> +#define CDNS_MCP_INT_PARITY BIT(8)
> #define CDNS_MCP_INT_CMD_ERR BIT(7)
> +#define CDNS_MCP_INT_RX_NE BIT(3)
> #define CDNS_MCP_INT_RX_WL BIT(2)
> #define CDNS_MCP_INT_TXE BIT(1)
> +#define CDNS_MCP_INT_TXF BIT(0)
>
> #define CDNS_MCP_INTSET 0x4C
>
> @@ -689,6 +692,11 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id)
> }
> }
>
> + if (int_status & CDNS_MCP_INT_PARITY) {
> + /* Parity error detected by Master */
> + dev_err_ratelimited(cdns->dev, "Parity error\n");
> + }
> +
> if (int_status & CDNS_MCP_INT_CTRL_CLASH) {
> /* Slave is driving bit slot during control word */
> dev_err_ratelimited(cdns->dev, "Bus clash for control word\n");
> @@ -761,10 +769,21 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
> cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1,
> CDNS_MCP_SLAVE_INTMASK1_MASK);
>
> + /* enable detection of slave state changes */
> mask = CDNS_MCP_INT_SLAVE_RSVD | CDNS_MCP_INT_SLAVE_ALERT |
> - CDNS_MCP_INT_SLAVE_ATTACH | CDNS_MCP_INT_SLAVE_NATTACH |
> - CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
> - CDNS_MCP_INT_RX_WL | CDNS_MCP_INT_IRQ | CDNS_MCP_INT_DPINT;
> + CDNS_MCP_INT_SLAVE_ATTACH | CDNS_MCP_INT_SLAVE_NATTACH;
> +
> + /* enable detection of bus issues */
> + mask |= CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
> + CDNS_MCP_INT_PARITY;
> +
> + /* no detection of port interrupts for now */
> +
> + /* enable detection of RX fifo level */
> + mask |= CDNS_MCP_INT_RX_WL;
> +
> + /* now enable all of the above */

I think this comment seems is at wrong line..?

> + mask |= CDNS_MCP_INT_IRQ;
>
> cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
>
> --
> 2.20.1

--
~Vinod

2019-08-02 22:15:38

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 13/40] soundwire: cadence_master: fix register definition for SLAVE_STATE

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
> wrong prefix and wrong macro.

Applied, thanks

--
~Vinod

2019-08-02 22:15:55

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 14/40] soundwire: cadence_master: fix definitions for INTSTAT0/1

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
> Two off-by-one errors: INTSTAT0 missed BIT(31) and INTSTAT1 is only
> defined on first 16 bits.

Applied, thanks

--
~Vinod

2019-08-02 22:33:49

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 08/40] soundwire: intel: remove BIOS work-arounds

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
> the values passed by all existing BIOS are fine, let's use them as is.
> The existing code must have been needed only on early prototypes.

Thanks for this, I am applying this.

>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/intel.c | 11 -----------
> 1 file changed, 11 deletions(-)
>
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index 51990b192dc0..c718c9c67a37 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -922,17 +922,6 @@ static int intel_prop_read(struct sdw_bus *bus)
> /* Initialize with default handler to read all DisCo properties */
> sdw_master_read_prop(bus);
>
> - /* BIOS is not giving some values correctly. So, lets override them */
> - bus->prop.num_clk_freq = 1;
> - bus->prop.clk_freq = devm_kcalloc(bus->dev, bus->prop.num_clk_freq,
> - sizeof(*bus->prop.clk_freq),
> - GFP_KERNEL);
> - if (!bus->prop.clk_freq)
> - return -ENOMEM;
> -
> - bus->prop.clk_freq[0] = bus->prop.max_clk_freq;
> - bus->prop.err_threshold = 5;
> -
> return 0;
> }
>
> --
> 2.20.1

--
~Vinod

2019-08-02 23:19:50

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 15/40] soundwire: cadence_master: handle multiple status reports per Slave

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
> When a Slave reports multiple status in the sticky bits, find the
> latest configuration from the mirror of the PING frame status and
> update the status directly.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 34 ++++++++++++++++++++++++------
> 1 file changed, 28 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 889fa2cd49ae..25d5c7267c15 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -643,13 +643,35 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
>
> /* first check if Slave reported multiple status */
> if (set_status > 1) {
> + u32 val;
> +
> dev_warn_ratelimited(cdns->dev,
> - "Slave reported multiple Status: %d\n",
> - mask);
> - /*
> - * TODO: we need to reread the status here by
> - * issuing a PING cmd
> - */
> + "Slave %d reported multiple Status: %d\n",
> + i, mask);
> +
> + /* re-check latest status extracted from PING commands */
> + val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
> + val >>= (i * 2);
> +
> + switch (val & 0x3) {
> + case 0:

why not case CDNS_MCP_SLAVE_INTSTAT_NPRESENT:

> + status[i] = SDW_SLAVE_UNATTACHED;
> + break;
> + case 1:
> + status[i] = SDW_SLAVE_ATTACHED;
> + break;
> + case 2:
> + status[i] = SDW_SLAVE_ALERT;
> + break;
> + default:
> + status[i] = SDW_SLAVE_RESERVED;
> + break;
> + }

we have same logic in the code block preceding this, maybe good idea to
write a helper and use for both

Also IIRC we can have multiple status set right?

--
~Vinod

2019-08-03 14:24:15

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 05/40] soundwire: intel: move interrupt enable after interrupt handler registration



On 8/2/19 6:53 AM, Vinod Koul wrote:
> On 25-07-19, 18:39, Pierre-Louis Bossart wrote:
>> Not sure why the existing code would enable interrupts without the
>> ability to deal with them.
>>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/intel.c | 4 ++--
>> 1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
>> index aeadc341c0a3..68832e613b1e 100644
>> --- a/drivers/soundwire/intel.c
>> +++ b/drivers/soundwire/intel.c
>> @@ -981,8 +981,6 @@ static int intel_probe(struct platform_device *pdev)
>> if (ret)
>> goto err_init;
>>
>> - ret = sdw_cdns_enable_interrupt(&sdw->cdns);
>> -
>> /* Read the PDI config and initialize cadence PDI */
>> intel_pdi_init(sdw, &config);
>> ret = sdw_cdns_pdi_init(&sdw->cdns, config);
>> @@ -1000,6 +998,8 @@ static int intel_probe(struct platform_device *pdev)
>> goto err_init;
>> }
>>
>> + ret = sdw_cdns_enable_interrupt(&sdw->cdns);
>
> we should also handle the return

yes, fixed already

2019-08-03 14:29:48

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 06/40] soundwire: intel: prevent possible dereference in hw_params



On 8/2/19 6:55 AM, Vinod Koul wrote:
> On 25-07-19, 18:39, Pierre-Louis Bossart wrote:
>> This should not happen in production systems but we should test for
>> all callback arguments before invoking the config_stream callback.
>
> so you are saying callback arg is mandatory, if so please document that
> assumption

no, what this says is that if a config_stream is provided then it needs
to have a valid argument.

I am not sure what you mean by "document that assumption", comment in
the code (where?) or SoundWire documentation?

>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/intel.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
>> index 68832e613b1e..497879dd9c0d 100644
>> --- a/drivers/soundwire/intel.c
>> +++ b/drivers/soundwire/intel.c
>> @@ -509,7 +509,7 @@ static int intel_config_stream(struct sdw_intel *sdw,
>> struct snd_soc_dai *dai,
>> struct snd_pcm_hw_params *hw_params, int link_id)
>> {
>> - if (sdw->res->ops && sdw->res->ops->config_stream)
>> + if (sdw->res->ops && sdw->res->ops->config_stream && sdw->res->arg)
>> return sdw->res->ops->config_stream(sdw->res->arg,
>> substream, dai, hw_params, link_id);
>>
>> --
>> 2.20.1
>

2019-08-03 14:31:31

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 09/40] soundwire: cadence_master: fix usage of CONFIG_UPDATE



On 8/2/19 7:03 AM, Vinod Koul wrote:
> On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
>
>> int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
>> {
>> - int ret;
>> -
>> _cdns_enable_interrupt(cdns);
>> - ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
>> - CDNS_MCP_CONFIG_UPDATE_BIT);
>> - if (ret < 0)
>> - dev_err(cdns->dev, "Config update timedout\n");
>
> I was expecting cdns_update_config() to be invoked here??
>
>>
>> - return ret;
>> + return 0;
>
> It would be better if we return a value here a not success always
>
>> @@ -943,7 +953,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
>>
>> cdns_writel(cdns, CDNS_MCP_CONFIG, val);
>>
>> - return 0;
>> + /* commit changes */
>> + ret = cdns_update_config(cdns);
>> +
>> + return ret;
>
> return cdns_update_config()

yes, all of this is fixed already.

2019-08-03 14:32:15

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 07/40] soundwire: intel: fix channel number reported by hardware



On 8/2/19 6:57 AM, Vinod Koul wrote:
> On 25-07-19, 18:39, Pierre-Louis Bossart wrote:
>> PDI2 reports an invalid count, force the correct hardware-supported
>> value
>>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/intel.c | 9 +++++++++
>> 1 file changed, 9 insertions(+)
>>
>> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
>> index 497879dd9c0d..51990b192dc0 100644
>> --- a/drivers/soundwire/intel.c
>> +++ b/drivers/soundwire/intel.c
>> @@ -401,6 +401,15 @@ intel_pdi_get_ch_cap(struct sdw_intel *sdw, unsigned int pdi_num, bool pcm)
>>
>> if (pcm) {
>> count = intel_readw(shim, SDW_SHIM_PCMSYCHC(link_id, pdi_num));
>> +
>> + /*
>> + * TODO: pdi number 2 reports channel count as 1 even though
>> + * it supports 8 channel. Performing hardcoding for pdi
>> + * number 2.
>> + */
>> + if (pdi_num == 2)
>> + count = 7;
>
> Is that true for all Intel controllers or some generations. Would it not
> be better to put this under some flag which is set on platform basis?

This is true of all controllers released so far.
We will change this if the hardware changes.

>
>> +
>> } else {
>> count = intel_readw(shim, SDW_SHIM_PDMSCAP(link_id));
>> count = ((count & SDW_SHIM_PDMSCAP_CPSS) >>
>> --
>> 2.20.1
>

2019-08-03 14:33:53

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 12/40] soundwire: cadence_master: revisit interrupt settings


>> @@ -761,10 +769,21 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
>> cdns_writel(cdns, CDNS_MCP_SLAVE_INTMASK1,
>> CDNS_MCP_SLAVE_INTMASK1_MASK);
>>
>> + /* enable detection of slave state changes */
>> mask = CDNS_MCP_INT_SLAVE_RSVD | CDNS_MCP_INT_SLAVE_ALERT |
>> - CDNS_MCP_INT_SLAVE_ATTACH | CDNS_MCP_INT_SLAVE_NATTACH |
>> - CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
>> - CDNS_MCP_INT_RX_WL | CDNS_MCP_INT_IRQ | CDNS_MCP_INT_DPINT;
>> + CDNS_MCP_INT_SLAVE_ATTACH | CDNS_MCP_INT_SLAVE_NATTACH;
>> +
>> + /* enable detection of bus issues */
>> + mask |= CDNS_MCP_INT_CTRL_CLASH | CDNS_MCP_INT_DATA_CLASH |
>> + CDNS_MCP_INT_PARITY;
>> +
>> + /* no detection of port interrupts for now */
>> +
>> + /* enable detection of RX fifo level */
>> + mask |= CDNS_MCP_INT_RX_WL;
>> +
>> + /* now enable all of the above */
>
> I think this comment seems is at wrong line..?
>
>> + mask |= CDNS_MCP_INT_IRQ;
>>
>> cdns_writel(cdns, CDNS_MCP_INTMASK, mask);

No it's at the right place.

This flag gates all others, if its value is zero then the value of all
other bits is irrelevant.

that's what I meant by 'all of the above'.


2019-08-03 14:36:59

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 15/40] soundwire: cadence_master: handle multiple status reports per Slave



On 8/2/19 7:20 AM, Vinod Koul wrote:
> On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
>> When a Slave reports multiple status in the sticky bits, find the
>> latest configuration from the mirror of the PING frame status and
>> update the status directly.
>>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/cadence_master.c | 34 ++++++++++++++++++++++++------
>> 1 file changed, 28 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
>> index 889fa2cd49ae..25d5c7267c15 100644
>> --- a/drivers/soundwire/cadence_master.c
>> +++ b/drivers/soundwire/cadence_master.c
>> @@ -643,13 +643,35 @@ static int cdns_update_slave_status(struct sdw_cdns *cdns,
>>
>> /* first check if Slave reported multiple status */
>> if (set_status > 1) {
>> + u32 val;
>> +
>> dev_warn_ratelimited(cdns->dev,
>> - "Slave reported multiple Status: %d\n",
>> - mask);
>> - /*
>> - * TODO: we need to reread the status here by
>> - * issuing a PING cmd
>> - */
>> + "Slave %d reported multiple Status: %d\n",
>> + i, mask);
>> +
>> + /* re-check latest status extracted from PING commands */
>> + val = cdns_readl(cdns, CDNS_MCP_SLAVE_STAT);
>> + val >>= (i * 2);
>> +
>> + switch (val & 0x3) {
>> + case 0:
>
> why not case CDNS_MCP_SLAVE_INTSTAT_NPRESENT:

ok

>
>> + status[i] = SDW_SLAVE_UNATTACHED;
>> + break;
>> + case 1:
>> + status[i] = SDW_SLAVE_ATTACHED;
>> + break;
>> + case 2:
>> + status[i] = SDW_SLAVE_ALERT;
>> + break;
>> + default:
>> + status[i] = SDW_SLAVE_RESERVED;
>> + break;
>> + }
>
> we have same logic in the code block preceding this, maybe good idea to
> write a helper and use for both

Yes, I am thinking about this. There are multiple cases where we want to
re-check the status and clear some bits, so helpers would be good.

>
> Also IIRC we can have multiple status set right?

Yes, the status bits are sticky and mirror all values reported in PING
frames. I am still working on how to clear those bits, there are cases
where we clear bits and end-up never hearing from that device ever
again. classic edge/level issue I suppose.

2019-08-03 14:58:20

by Vinod Koul

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 06/40] soundwire: intel: prevent possible dereference in hw_params

On 02-08-19, 10:16, Pierre-Louis Bossart wrote:
>
>
> On 8/2/19 6:55 AM, Vinod Koul wrote:
> > On 25-07-19, 18:39, Pierre-Louis Bossart wrote:
> > > This should not happen in production systems but we should test for
> > > all callback arguments before invoking the config_stream callback.
> >
> > so you are saying callback arg is mandatory, if so please document that
> > assumption
>
> no, what this says is that if a config_stream is provided then it needs to
> have a valid argument.

well typically args are not mandatory..

> I am not sure what you mean by "document that assumption", comment in the
> code (where?) or SoundWire documentation?

The callback documentation which in this is in include/linux/soundwire/sdw_intel.h

--
~Vinod

2019-08-03 14:58:51

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 15/40] soundwire: cadence_master: handle multiple status reports per Slave

On 02-08-19, 10:29, Pierre-Louis Bossart wrote:
> On 8/2/19 7:20 AM, Vinod Koul wrote:
> > On 25-07-19, 18:40, Pierre-Louis Bossart wrote:

> > > + status[i] = SDW_SLAVE_UNATTACHED;
> > > + break;
> > > + case 1:
> > > + status[i] = SDW_SLAVE_ATTACHED;
> > > + break;
> > > + case 2:
> > > + status[i] = SDW_SLAVE_ALERT;
> > > + break;
> > > + default:
> > > + status[i] = SDW_SLAVE_RESERVED;
> > > + break;
> > > + }
> >
> > we have same logic in the code block preceding this, maybe good idea to
> > write a helper and use for both
>
> Yes, I am thinking about this. There are multiple cases where we want to
> re-check the status and clear some bits, so helpers would be good.
>
> >
> > Also IIRC we can have multiple status set right?
>
> Yes, the status bits are sticky and mirror all values reported in PING
> frames. I am still working on how to clear those bits, there are cases where
> we clear bits and end-up never hearing from that device ever again. classic
> edge/level issue I suppose.

Then the case logic above doesn't work, it should be like the code block
preceding this..

Thanks
--
~Vinod

2019-08-03 15:47:31

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 15/40] soundwire: cadence_master: handle multiple status reports per Slave



On 8/2/19 11:01 AM, Vinod Koul wrote:
> On 02-08-19, 10:29, Pierre-Louis Bossart wrote:
>> On 8/2/19 7:20 AM, Vinod Koul wrote:
>>> On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
>
>>>> + status[i] = SDW_SLAVE_UNATTACHED;
>>>> + break;
>>>> + case 1:
>>>> + status[i] = SDW_SLAVE_ATTACHED;
>>>> + break;
>>>> + case 2:
>>>> + status[i] = SDW_SLAVE_ALERT;
>>>> + break;
>>>> + default:
>>>> + status[i] = SDW_SLAVE_RESERVED;
>>>> + break;
>>>> + }
>>>
>>> we have same logic in the code block preceding this, maybe good idea to
>>> write a helper and use for both
>>
>> Yes, I am thinking about this. There are multiple cases where we want to
>> re-check the status and clear some bits, so helpers would be good.
>>
>>>
>>> Also IIRC we can have multiple status set right?
>>
>> Yes, the status bits are sticky and mirror all values reported in PING
>> frames. I am still working on how to clear those bits, there are cases where
>> we clear bits and end-up never hearing from that device ever again. classic
>> edge/level issue I suppose.
>
> Then the case logic above doesn't work, it should be like the code block
> preceding this..

what I was referring to already is a problem even in single status mode.

Let's say for example that a device shows up as Device0, then we try to
enumerate it and program a non-zero device number. If that fails, we
currently clear the Attached status for Device0, so will never have an
interrupt ever again. The device is there, attached as Device0, but
we've lost the single opportunity to make it usable. The link is in most
cases going to be extremely reliable, but if we know of state machines
that lead to a terminal state then we should proactively have a recovery
mechanism to avoid complicated debug down the road for cases where the
hardware has transient issues.

For the multiple status case, we will have to look at the details and
figure out which of the flags get cleared and which ones don't.

One certainty is that we absolutely have to track IO errors in interrupt
context. They are recoverable in regular context but not quite in
interrupt context if we clear the status bits unconditionally.

Maybe a tangent here but to be transparent there are really multiple
topics we are tracking at the moment:

1. error handling in interrupts. I found a leak where if a device goes
in the weeds while we program its device number and resynchronizes then
we allocate a new device number instead of reusing the initial one. The
bit clearing is also to be checked as explained above.

2. module dependencies: there is a race condition leading to a kernel
oops if the Slave probe is not complete before the .update_status is
invoked.

3. jack detection. The jack detection routine is called as a result of
an imp-def Slave interrupt. We never documented the assumption that if
this jack detection takes time then it needs to be done offline, e.g. in
a work queue. Or if we still want it to be done in a the interrupt
thread then we need to re-enable interrupts earlier, otherwise one
device can stop interrupt handling for a fairly long duration.

4. streaming stop on link errors. We've seen in tests that if you reset
the link or a Slave device with debugfs while audio is playing then
streaming continues. This condition could happen if a device loses sync,
and the spec says the Slave needs to reset its channel enable bits. At
the command level, we handle this situation and will recover, but there
is no notification to the ALSA layers to try and recover on the PCM side
of things (as if it were an underflow condition). We also try to disable
a stream but get all kinds of errors since it's lost state.

All of those points are corner cases but they are important to solve for
actual products.

2019-08-03 15:55:49

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 06/40] soundwire: intel: prevent possible dereference in hw_params



On 8/2/19 10:57 AM, Vinod Koul wrote:
> On 02-08-19, 10:16, Pierre-Louis Bossart wrote:
>>
>>
>> On 8/2/19 6:55 AM, Vinod Koul wrote:
>>> On 25-07-19, 18:39, Pierre-Louis Bossart wrote:
>>>> This should not happen in production systems but we should test for
>>>> all callback arguments before invoking the config_stream callback.
>>>
>>> so you are saying callback arg is mandatory, if so please document that
>>> assumption
>>
>> no, what this says is that if a config_stream is provided then it needs to
>> have a valid argument.
>
> well typically args are not mandatory..
>
>> I am not sure what you mean by "document that assumption", comment in the
>> code (where?) or SoundWire documentation?
>
> The callback documentation which in this is in include/linux/soundwire/sdw_intel.h
>

/**
* struct sdw_intel_ops: Intel audio driver callback ops
*
* @config_stream: configure the stream with the hw_params
*/
struct sdw_intel_ops {
int (*config_stream)(void *arg, void *substream,
void *dai, void *hw_params, int stream_num);
};

all parameters are mandatory really, not sure what you are trying to get at.

2019-08-03 15:58:24

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
> Not all platforms support runtime_pm for now, let's use runtime_pm
> only when enabled.

We discussed this with Ulf sometime back and it was a consensus the core
should handle it, but that may take a while.

So that led me to explore what others do notably ASoC, based on this I
feel we should not check the error code. We handle the non streaming
case here but streaming is handled in ASoC which doesnt check the return

Pierre, can you verify the below patch and let me know if that is fine
for Intel platforms

--- >8 ---

From: Vinod Koul <[email protected]>
Date: Fri, 2 Aug 2019 22:15:11 +0530
Subject: [PATCH] soundwire: dont check return of pm_runtime_get_sync()

Soundwire core checks pm_runtime_get_sync() return. But in case the
driver has not enabled runtime pm we get an error.

To fix this, dont check the return. We handle the non streaming case in
framework but streaming case has similar handling in ASoC so make it
same across use cases

Signed-off-by: Vinod Koul <[email protected]>
---
drivers/soundwire/bus.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
index fe745830a261..9cdf7e9e0852 100644
--- a/drivers/soundwire/bus.c
+++ b/drivers/soundwire/bus.c
@@ -326,9 +326,7 @@ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
if (ret < 0)
return ret;

- ret = pm_runtime_get_sync(slave->bus->dev);
- if (ret < 0)
- return ret;
+ pm_runtime_get_sync(slave->bus->dev);

ret = sdw_transfer(slave->bus, &msg);
pm_runtime_put(slave->bus->dev);
@@ -354,9 +352,7 @@ int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
if (ret < 0)
return ret;

- ret = pm_runtime_get_sync(slave->bus->dev);
- if (ret < 0)
- return ret;
+ pm_runtime_get_sync(slave->bus->dev);

ret = sdw_transfer(slave->bus, &msg);
pm_runtime_put(slave->bus->dev);
--
2.20.1



>
> Suggested-by: Srinivas Kandagatla <[email protected]>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/bus.c | 25 ++++++++++++++++---------
> 1 file changed, 16 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
> index 5ad4109dc72f..0a45dc5713df 100644
> --- a/drivers/soundwire/bus.c
> +++ b/drivers/soundwire/bus.c
> @@ -332,12 +332,16 @@ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
> if (ret < 0)
> return ret;
>
> - ret = pm_runtime_get_sync(slave->bus->dev);
> - if (ret < 0)
> - return ret;
> + if (pm_runtime_enabled(slave->bus->dev)) {
> + ret = pm_runtime_get_sync(slave->bus->dev);
> + if (ret < 0)
> + return ret;
> + }
>
> ret = sdw_transfer(slave->bus, &msg);
> - pm_runtime_put(slave->bus->dev);
> +
> + if (pm_runtime_enabled(slave->bus->dev))
> + pm_runtime_put(slave->bus->dev);
>
> return ret;
> }
> @@ -359,13 +363,16 @@ int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
> slave->dev_num, SDW_MSG_FLAG_WRITE, val);
> if (ret < 0)
> return ret;
> -
> - ret = pm_runtime_get_sync(slave->bus->dev);
> - if (ret < 0)
> - return ret;
> + if (pm_runtime_enabled(slave->bus->dev)) {
> + ret = pm_runtime_get_sync(slave->bus->dev);
> + if (ret < 0)
> + return ret;
> + }
>
> ret = sdw_transfer(slave->bus, &msg);
> - pm_runtime_put(slave->bus->dev);
> +
> + if (pm_runtime_enabled(slave->bus->dev))
> + pm_runtime_put(slave->bus->dev);
>
> return ret;
> }
> --
> 2.20.1

--
~Vinod

2019-08-03 16:00:07

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 18/40] soundwire: bus: split handling of Device0 events

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
> Assigning a device number to a Slave will result in additional events
> when it reports its status in a PING frame. There is no point in
> dealing with all the other devices in a loop, this can be done when a
> non-device0 event happens.

Applied, thanks

--
~Vinod

2019-08-03 16:02:14

by Vinod Koul

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 21/40] soundwire: export helpers to find row and column values

On 26-07-19, 10:26, Pierre-Louis Bossart wrote:
>
>
> On 7/26/19 9:43 AM, Guennadi Liakhovetski wrote:
> > On Thu, Jul 25, 2019 at 06:40:13PM -0500, Pierre-Louis Bossart wrote:
> > > Add a prefix for common tables and export 2 helpers to set the frame
> > > shapes based on row/col values.
> > >
> > > Signed-off-by: Pierre-Louis Bossart <[email protected]>
> > > ---
> > > drivers/soundwire/bus.h | 7 +++++--
> > > drivers/soundwire/stream.c | 14 ++++++++------
> > > 2 files changed, 13 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
> > > index 06ac4adb0074..c57c9c23f6ca 100644
> > > --- a/drivers/soundwire/bus.h
> > > +++ b/drivers/soundwire/bus.h
> > > @@ -73,8 +73,11 @@ struct sdw_msg {
> > > #define SDW_DOUBLE_RATE_FACTOR 2
> > > -extern int rows[SDW_FRAME_ROWS];
> > > -extern int cols[SDW_FRAME_COLS];
> > > +extern int sdw_rows[SDW_FRAME_ROWS];
> > > +extern int sdw_cols[SDW_FRAME_COLS];
> >
> > So these arrays actually have to be exported? In the current (5.2) sources they
> > seem to only be used in stream.c, maybe make them static there?
> >
> > > +
> > > +int sdw_find_row_index(int row);
> > > +int sdw_find_col_index(int col);
>
> yes, they need to be exported, they are used by the allocation algorithm (in
> Patch 27).
> Others will need this for non-Intel solutions, it's really a part of the
> standard definition and should be shared.
> I can improve the commit message to make this explicit.

Yes that would help! And also move it to before it's usage so it clear
that it is used in next one.

--
~Vinod

2019-08-03 16:15:03

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 25/40] soundwire: intel: use BIOS information to set clock dividers

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
> The BIOS provides an Intel-specific property, let's use it to avoid
> hard-coded clock dividers.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 26 ++++++++++++++++++++++----
> drivers/soundwire/intel.c | 26 ++++++++++++++++++++++++++
> include/linux/soundwire/sdw.h | 2 ++

ah, intel patch touching bunch of things!

> 3 files changed, 50 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index d84344e29f71..10ebcef2e84e 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -173,8 +173,6 @@
> #define CDNS_PDI_CONFIG_PORT GENMASK(4, 0)
>
> /* Driver defaults */
> -
> -#define CDNS_DEFAULT_CLK_DIVIDER 0
> #define CDNS_DEFAULT_SSP_INTERVAL 0x18
> #define CDNS_TX_TIMEOUT 2000
>
> @@ -973,7 +971,10 @@ static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
> */
> int sdw_cdns_init(struct sdw_cdns *cdns)
> {
> + struct sdw_bus *bus = &cdns->bus;
> + struct sdw_master_prop *prop = &bus->prop;
> u32 val;
> + int divider;
> int ret;
>
> /* Exit clock stop */
> @@ -985,9 +986,17 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
> }
>
> /* Set clock divider */
> + divider = (prop->mclk_freq / prop->max_clk_freq) - 1;
> val = cdns_readl(cdns, CDNS_MCP_CLK_CTRL0);
> - val |= CDNS_DEFAULT_CLK_DIVIDER;
> + val |= divider;
> cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
> + cdns_writel(cdns, CDNS_MCP_CLK_CTRL1, val);
> +
> + pr_err("plb: mclk %d max_freq %d divider %d register %x\n",
> + prop->mclk_freq,
> + prop->max_clk_freq,
> + divider,
> + val);

I guess you forgot to remove this!

>
> /* Set the default frame shape */
> val = cdns_set_default_frame_shape(prop->default_row,
> @@ -1035,6 +1044,7 @@ EXPORT_SYMBOL(sdw_cdns_init);
>
> int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
> {
> + struct sdw_master_prop *prop = &bus->prop;
> struct sdw_cdns *cdns = bus_to_cdns(bus);
> int mcp_clkctrl_off, mcp_clkctrl;
> int divider;
> @@ -1044,7 +1054,9 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
> return -EINVAL;
> }
>
> - divider = (params->max_dr_freq / params->curr_dr_freq) - 1;
> + divider = prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR /
> + params->curr_dr_freq;
> + divider--; /* divider is 1/(N+1) */
>
> if (params->next_bank)
> mcp_clkctrl_off = CDNS_MCP_CLK_CTRL1;
> @@ -1055,6 +1067,12 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
> mcp_clkctrl |= divider;
> cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl);
>
> + pr_err("plb: mclk * 2 %d curr_dr_freq %d divider %d register %x\n",
> + prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR,
> + params->curr_dr_freq,
> + divider,
> + mcp_clkctrl);

here too!

> +
> return 0;
> }
> EXPORT_SYMBOL(cdns_bus_conf);
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index c718c9c67a37..796ac2bc8cea 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -917,11 +917,37 @@ static int intel_register_dai(struct sdw_intel *sdw)
> dais, num_dai);
> }
>
> +static int sdw_master_read_intel_prop(struct sdw_bus *bus)
> +{
> + struct sdw_master_prop *prop = &bus->prop;
> + struct fwnode_handle *link;
> + char name[32];
> + int nval, i;
> +
> + /* Find master handle */
> + snprintf(name, sizeof(name),
> + "mipi-sdw-link-%d-subproperties", bus->link_id);
> +
> + link = device_get_named_child_node(bus->dev, name);
> + if (!link) {
> + dev_err(bus->dev, "Master node %s not found\n", name);
> + return -EIO;
> + }
> +
> + fwnode_property_read_u32(link,
> + "intel-sdw-ip-clock",
> + &prop->mclk_freq);
> + return 0;
> +}
> +
> static int intel_prop_read(struct sdw_bus *bus)
> {
> /* Initialize with default handler to read all DisCo properties */
> sdw_master_read_prop(bus);
>
> + /* read Intel-specific properties */
> + sdw_master_read_intel_prop(bus);
> +
> return 0;
> }
>
> diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
> index 31d1e8acf25b..b6acc436ac80 100644
> --- a/include/linux/soundwire/sdw.h
> +++ b/include/linux/soundwire/sdw.h
> @@ -379,6 +379,7 @@ struct sdw_slave_prop {
> * @dynamic_frame: Dynamic frame shape supported
> * @err_threshold: Number of times that software may retry sending a single
> * command
> + * @mclk_freq: clock reference passed to SoundWire Master, in Hz.
> */
> struct sdw_master_prop {
> u32 revision;
> @@ -393,6 +394,7 @@ struct sdw_master_prop {
> u32 default_col;
> bool dynamic_frame;
> u32 err_threshold;
> + u32 mclk_freq;

Other than debug artifacts this looks sane, but can you split up the
cadence and intel parts into different patches please

--
~Vinod

2019-08-03 16:17:19

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 17/40] soundwire: bus: use runtime_pm_get_sync/pm when enabled

On 8/2/19 11:58 AM, Vinod Koul wrote:
> On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
>> Not all platforms support runtime_pm for now, let's use runtime_pm
>> only when enabled.
>
> We discussed this with Ulf sometime back and it was a consensus the core
> should handle it, but that may take a while.
>
> So that led me to explore what others do notably ASoC, based on this I
> feel we should not check the error code. We handle the non streaming
> case here but streaming is handled in ASoC which doesnt check the return
>
> Pierre, can you verify the below patch and let me know if that is fine
> for Intel platforms

So if for some reason we cannot resume, then we'd still initiate a
transaction and have even more issues to sort out.

Fail big and fail early would really be my preference.

Also the user of this function is largely the Slave driver, which
typically doesn't do any streaming operation but controls the imp-def
registers. The bus driver will only use this routine for standard
registers and that's a very small part of the total traffic.

>
> --- >8 ---
>
> From: Vinod Koul <[email protected]>
> Date: Fri, 2 Aug 2019 22:15:11 +0530
> Subject: [PATCH] soundwire: dont check return of pm_runtime_get_sync()
>
> Soundwire core checks pm_runtime_get_sync() return. But in case the
> driver has not enabled runtime pm we get an error.
>
> To fix this, dont check the return. We handle the non streaming case in
> framework but streaming case has similar handling in ASoC so make it
> same across use cases
>
> Signed-off-by: Vinod Koul <[email protected]>
> ---
> drivers/soundwire/bus.c | 8 ++------
> 1 file changed, 2 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
> index fe745830a261..9cdf7e9e0852 100644
> --- a/drivers/soundwire/bus.c
> +++ b/drivers/soundwire/bus.c
> @@ -326,9 +326,7 @@ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
> if (ret < 0)
> return ret;
>
> - ret = pm_runtime_get_sync(slave->bus->dev);
> - if (ret < 0)
> - return ret;
> + pm_runtime_get_sync(slave->bus->dev);
>
> ret = sdw_transfer(slave->bus, &msg);
> pm_runtime_put(slave->bus->dev);
> @@ -354,9 +352,7 @@ int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val)
> if (ret < 0)
> return ret;
>
> - ret = pm_runtime_get_sync(slave->bus->dev);
> - if (ret < 0)
> - return ret;
> + pm_runtime_get_sync(slave->bus->dev);
>
> ret = sdw_transfer(slave->bus, &msg);
> pm_runtime_put(slave->bus->dev);
>

2019-08-03 16:18:34

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 26/40] soundwire: cadence_master: fix divider setting in clock register

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
> From: Rander Wang <[email protected]>
>
> The existing code uses an OR operation which would mix the original
> divider setting with the new one, resulting in an invalid
> configuration that can make codecs hang.

This looked fine but fails to apply, feel free to send as a fix

--
~Vinod

2019-08-03 16:20:44

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 20/40] soundwire: prototypes for suspend/resume

On 8/2/19 12:03 PM, Vinod Koul wrote:
> On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
>
> Please do provide the changelog on why this change is needed.

not needed for now, will remove.

>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/cadence_master.h | 3 +++
>> 1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
>> index c0bf6ff00a44..d375bbfead18 100644
>> --- a/drivers/soundwire/cadence_master.h
>> +++ b/drivers/soundwire/cadence_master.h
>> @@ -165,6 +165,9 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
>>
>> void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
>>
>> +int sdw_cdns_suspend(struct sdw_cdns *cdns);
>> +bool sdw_cdns_check_resume_status(struct sdw_cdns *cdns);
>> +
>> int sdw_cdns_get_stream(struct sdw_cdns *cdns,
>> struct sdw_cdns_streams *stream,
>> u32 ch, u32 dir);
>> --
>> 2.20.1
>

2019-08-03 16:31:12

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 24/40] soundwire: cadence_master: use BIOS defaults for frame shape

On 8/2/19 12:10 PM, Vinod Koul wrote:
> On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
>> Remove hard-coding and use BIOS values. If they are wrong use default
>
> BIOS :) this is cadence, am sure this can be used outside BIOS :D
>
> It would be better to say firmware (ACPI/DT)

yes

>
>> 48x2 frame shape.
>>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/cadence_master.c | 19 +++++++++++++++++--
>> 1 file changed, 17 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
>> index 442f78c00f09..d84344e29f71 100644
>> --- a/drivers/soundwire/cadence_master.c
>> +++ b/drivers/soundwire/cadence_master.c
>> @@ -175,7 +175,6 @@
>> /* Driver defaults */
>>
>> #define CDNS_DEFAULT_CLK_DIVIDER 0
>> -#define CDNS_DEFAULT_FRAME_SHAPE 0x30
>> #define CDNS_DEFAULT_SSP_INTERVAL 0x18
>> #define CDNS_TX_TIMEOUT 2000
>>
>> @@ -954,6 +953,20 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
>> }
>> EXPORT_SYMBOL(sdw_cdns_pdi_init);
>>
>> +static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
>> +{
>> + u32 val;
>> + int c;
>> + int r;
>
> This can be in single line!

one line per variable is what I prefer.

>
>> +
>> + r = sdw_find_row_index(n_rows);
>> + c = sdw_find_col_index(n_cols);
>> +
>> + val = (r << 3) | c;
>
> Magic 3?

yes fixed already.

2019-08-03 16:35:36

by Vinod Koul

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 31/40] soundwire: intel: move shutdown() callback and don't export symbol

On 26-07-19, 09:46, Pierre-Louis Bossart wrote:
>
>
> On 7/26/19 5:38 AM, Cezary Rojewski wrote:
> > On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
> > > +void intel_shutdown(struct snd_pcm_substream *substream,
> > > +??????????? struct snd_soc_dai *dai)
> > > +{
> > > +??? struct sdw_cdns_dma_data *dma;
> > > +
> > > +??? dma = snd_soc_dai_get_dma_data(dai, substream);
> > > +??? if (!dma)
> > > +??????? return;
> > > +
> > > +??? snd_soc_dai_set_dma_data(dai, substream, NULL);
> > > +??? kfree(dma);
> > > +}
> >
> > Correct me if I'm wrong, but do we really need to _get_dma_ here?
> > _set_dma_ seems bulletproof, same for kfree.
>
> I must admit I have no idea why we have a reference to DMAs here, this looks
> like an abuse to store a dai-specific context, and the initial test looks
> like copy-paste to detect invalid configs, as done in other callbacks. Vinod
> and Sanyog might have more history than me here.

I dont see snd_soc_dai_set_dma_data() call for
sdw_cdns_dma_data so somthing is missing (at least in upstream code)

IIRC we should have a snd_soc_dai_set_dma_data() in alloc or some
initialization routine and we free it here.. Sanyog?

--
~Vinod

2019-08-03 16:35:38

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 26/40] soundwire: cadence_master: fix divider setting in clock register

On 8/2/19 12:19 PM, Vinod Koul wrote:
> On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
>> From: Rander Wang <[email protected]>
>>
>> The existing code uses an OR operation which would mix the original
>> divider setting with the new one, resulting in an invalid
>> configuration that can make codecs hang.
>
> This looked fine but fails to apply, feel free to send as a fix

likely because it's on top of patch 25



2019-08-03 16:36:28

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 25/40] soundwire: intel: use BIOS information to set clock dividers

On 8/2/19 12:17 PM, Vinod Koul wrote:
> On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
>> The BIOS provides an Intel-specific property, let's use it to avoid
>> hard-coded clock dividers.
>>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/cadence_master.c | 26 ++++++++++++++++++++++----
>> drivers/soundwire/intel.c | 26 ++++++++++++++++++++++++++
>> include/linux/soundwire/sdw.h | 2 ++
>
> ah, intel patch touching bunch of things!

not really, it's more removing Intel-specific configs in the Cadence parts.

>
>> 3 files changed, 50 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
>> index d84344e29f71..10ebcef2e84e 100644
>> --- a/drivers/soundwire/cadence_master.c
>> +++ b/drivers/soundwire/cadence_master.c
>> @@ -173,8 +173,6 @@
>> #define CDNS_PDI_CONFIG_PORT GENMASK(4, 0)
>>
>> /* Driver defaults */
>> -
>> -#define CDNS_DEFAULT_CLK_DIVIDER 0
>> #define CDNS_DEFAULT_SSP_INTERVAL 0x18
>> #define CDNS_TX_TIMEOUT 2000
>>
>> @@ -973,7 +971,10 @@ static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
>> */
>> int sdw_cdns_init(struct sdw_cdns *cdns)
>> {
>> + struct sdw_bus *bus = &cdns->bus;
>> + struct sdw_master_prop *prop = &bus->prop;
>> u32 val;
>> + int divider;
>> int ret;
>>
>> /* Exit clock stop */
>> @@ -985,9 +986,17 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
>> }
>>
>> /* Set clock divider */
>> + divider = (prop->mclk_freq / prop->max_clk_freq) - 1;
>> val = cdns_readl(cdns, CDNS_MCP_CLK_CTRL0);
>> - val |= CDNS_DEFAULT_CLK_DIVIDER;
>> + val |= divider;
>> cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
>> + cdns_writel(cdns, CDNS_MCP_CLK_CTRL1, val);
>> +
>> + pr_err("plb: mclk %d max_freq %d divider %d register %x\n",
>> + prop->mclk_freq,
>> + prop->max_clk_freq,
>> + divider,
>> + val);
>
> I guess you forgot to remove this!

yes, fixed already

>
>>
>> /* Set the default frame shape */
>> val = cdns_set_default_frame_shape(prop->default_row,
>> @@ -1035,6 +1044,7 @@ EXPORT_SYMBOL(sdw_cdns_init);
>>
>> int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
>> {
>> + struct sdw_master_prop *prop = &bus->prop;
>> struct sdw_cdns *cdns = bus_to_cdns(bus);
>> int mcp_clkctrl_off, mcp_clkctrl;
>> int divider;
>> @@ -1044,7 +1054,9 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
>> return -EINVAL;
>> }
>>
>> - divider = (params->max_dr_freq / params->curr_dr_freq) - 1;
>> + divider = prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR /
>> + params->curr_dr_freq;
>> + divider--; /* divider is 1/(N+1) */
>>
>> if (params->next_bank)
>> mcp_clkctrl_off = CDNS_MCP_CLK_CTRL1;
>> @@ -1055,6 +1067,12 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
>> mcp_clkctrl |= divider;
>> cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl);
>>
>> + pr_err("plb: mclk * 2 %d curr_dr_freq %d divider %d register %x\n",
>> + prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR,
>> + params->curr_dr_freq,
>> + divider,
>> + mcp_clkctrl);
>
> here too!

yep

>
>> +
>> return 0;
>> }
>> EXPORT_SYMBOL(cdns_bus_conf);
>> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
>> index c718c9c67a37..796ac2bc8cea 100644
>> --- a/drivers/soundwire/intel.c
>> +++ b/drivers/soundwire/intel.c
>> @@ -917,11 +917,37 @@ static int intel_register_dai(struct sdw_intel *sdw)
>> dais, num_dai);
>> }
>>
>> +static int sdw_master_read_intel_prop(struct sdw_bus *bus)
>> +{
>> + struct sdw_master_prop *prop = &bus->prop;
>> + struct fwnode_handle *link;
>> + char name[32];
>> + int nval, i;
>> +
>> + /* Find master handle */
>> + snprintf(name, sizeof(name),
>> + "mipi-sdw-link-%d-subproperties", bus->link_id);
>> +
>> + link = device_get_named_child_node(bus->dev, name);
>> + if (!link) {
>> + dev_err(bus->dev, "Master node %s not found\n", name);
>> + return -EIO;
>> + }
>> +
>> + fwnode_property_read_u32(link,
>> + "intel-sdw-ip-clock",
>> + &prop->mclk_freq);
>> + return 0;
>> +}
>> +
>> static int intel_prop_read(struct sdw_bus *bus)
>> {
>> /* Initialize with default handler to read all DisCo properties */
>> sdw_master_read_prop(bus);
>>
>> + /* read Intel-specific properties */
>> + sdw_master_read_intel_prop(bus);
>> +
>> return 0;
>> }
>>
>> diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
>> index 31d1e8acf25b..b6acc436ac80 100644
>> --- a/include/linux/soundwire/sdw.h
>> +++ b/include/linux/soundwire/sdw.h
>> @@ -379,6 +379,7 @@ struct sdw_slave_prop {
>> * @dynamic_frame: Dynamic frame shape supported
>> * @err_threshold: Number of times that software may retry sending a single
>> * command
>> + * @mclk_freq: clock reference passed to SoundWire Master, in Hz.
>> */
>> struct sdw_master_prop {
>> u32 revision;
>> @@ -393,6 +394,7 @@ struct sdw_master_prop {
>> u32 default_col;
>> bool dynamic_frame;
>> u32 err_threshold;
>> + u32 mclk_freq;
>
> Other than debug artifacts this looks sane, but can you split up the
> cadence and intel parts into different patches please

ok, i'll split in 3. prototype, intel, cadence.

2019-08-03 16:37:42

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 34/40] soundwire: intel: ignore disabled links for suspend/resume

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:

Please add explanation why..

> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/intel.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index 1477c35f616f..a976480d6f36 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -1161,6 +1161,12 @@ static int intel_suspend(struct device *dev)
>
> sdw = dev_get_drvdata(dev);
>
> + if (sdw->cdns.bus.prop.hw_disabled) {
> + dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
> + sdw->cdns.bus.link_id);
> + return 0;
> + }
> +
> ret = intel_link_power_down(sdw);
> if (ret) {
> dev_err(dev, "Link power down failed: %d", ret);
> @@ -1179,6 +1185,12 @@ static int intel_resume(struct device *dev)
>
> sdw = dev_get_drvdata(dev);
>
> + if (sdw->cdns.bus.prop.hw_disabled) {
> + dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
> + sdw->cdns.bus.link_id);
> + return 0;
> + }
> +
> ret = intel_init(sdw);
> if (ret) {
> dev_err(dev, "%s failed: %d", __func__, ret);
> --
> 2.20.1

--
~Vinod

2019-08-03 16:37:55

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 35/40] soundwire: intel: export helper to exit reset

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:

Here as well

> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 9 +++++++--
> drivers/soundwire/cadence_master.h | 1 +
> drivers/soundwire/intel.c | 4 ++++
> 3 files changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 4a189e487830..f486fe15fb46 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -780,7 +780,11 @@ EXPORT_SYMBOL(sdw_cdns_thread);
> * init routines
> */
>
> -static int do_reset(struct sdw_cdns *cdns)
> +/**
> + * sdw_cdns_exit_reset() - Program reset parameters and start bus operations
> + * @cdns: Cadence instance
> + */
> +int sdw_cdns_exit_reset(struct sdw_cdns *cdns)
> {
> int ret;
>
> @@ -804,6 +808,7 @@ static int do_reset(struct sdw_cdns *cdns)
>
> return ret;
> }
> +EXPORT_SYMBOL(sdw_cdns_exit_reset);
>
> /**
> * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
> @@ -839,7 +844,7 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
>
> cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
>
> - return do_reset(cdns);
> + return 0;
> }
> EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
>
> diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
> index de97bc22acb7..2b551f9226f3 100644
> --- a/drivers/soundwire/cadence_master.h
> +++ b/drivers/soundwire/cadence_master.h
> @@ -161,6 +161,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
> int sdw_cdns_init(struct sdw_cdns *cdns);
> int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
> struct sdw_cdns_stream_config config);
> +int sdw_cdns_exit_reset(struct sdw_cdns *cdns);
> int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
>
> void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index a976480d6f36..9ebe38e4d979 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -1112,6 +1112,8 @@ static int intel_probe(struct platform_device *pdev)
>
> ret = sdw_cdns_enable_interrupt(&sdw->cdns);
>
> + ret = sdw_cdns_exit_reset(&sdw->cdns);
> +
> /* Register DAIs */
> ret = intel_register_dai(sdw);
> if (ret) {
> @@ -1199,6 +1201,8 @@ static int intel_resume(struct device *dev)
>
> sdw_cdns_enable_interrupt(&sdw->cdns);
>
> + ret = sdw_cdns_exit_reset(&sdw->cdns);
> +
> return ret;
> }
>
> --
> 2.20.1

--
~Vinod

2019-08-03 16:39:04

by Vinod Koul

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 06/40] soundwire: intel: prevent possible dereference in hw_params

On 02-08-19, 11:52, Pierre-Louis Bossart wrote:
>
>
> On 8/2/19 10:57 AM, Vinod Koul wrote:
> > On 02-08-19, 10:16, Pierre-Louis Bossart wrote:
> > >
> > >
> > > On 8/2/19 6:55 AM, Vinod Koul wrote:
> > > > On 25-07-19, 18:39, Pierre-Louis Bossart wrote:
> > > > > This should not happen in production systems but we should test for
> > > > > all callback arguments before invoking the config_stream callback.
> > > >
> > > > so you are saying callback arg is mandatory, if so please document that
> > > > assumption
> > >
> > > no, what this says is that if a config_stream is provided then it needs to
> > > have a valid argument.
> >
> > well typically args are not mandatory..
> >
> > > I am not sure what you mean by "document that assumption", comment in the
> > > code (where?) or SoundWire documentation?
> >
> > The callback documentation which in this is in include/linux/soundwire/sdw_intel.h
> >
>
> /**
> * struct sdw_intel_ops: Intel audio driver callback ops
> *
> * @config_stream: configure the stream with the hw_params
> */
> struct sdw_intel_ops {
> int (*config_stream)(void *arg, void *substream,
> void *dai, void *hw_params, int stream_num);
> };
>
> all parameters are mandatory really, not sure what you are trying to get at.

It would be good to make a note that argument is mandatory!

Thanks
--
~Vinod

2019-08-03 16:40:52

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 35/40] soundwire: intel: export helper to exit reset

On 8/2/19 12:31 PM, Vinod Koul wrote:
> On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
>
> Here as well

I squashed this with earlier patches to fix the init sequence in one shot

>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/cadence_master.c | 9 +++++++--
>> drivers/soundwire/cadence_master.h | 1 +
>> drivers/soundwire/intel.c | 4 ++++
>> 3 files changed, 12 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
>> index 4a189e487830..f486fe15fb46 100644
>> --- a/drivers/soundwire/cadence_master.c
>> +++ b/drivers/soundwire/cadence_master.c
>> @@ -780,7 +780,11 @@ EXPORT_SYMBOL(sdw_cdns_thread);
>> * init routines
>> */
>>
>> -static int do_reset(struct sdw_cdns *cdns)
>> +/**
>> + * sdw_cdns_exit_reset() - Program reset parameters and start bus operations
>> + * @cdns: Cadence instance
>> + */
>> +int sdw_cdns_exit_reset(struct sdw_cdns *cdns)
>> {
>> int ret;
>>
>> @@ -804,6 +808,7 @@ static int do_reset(struct sdw_cdns *cdns)
>>
>> return ret;
>> }
>> +EXPORT_SYMBOL(sdw_cdns_exit_reset);
>>
>> /**
>> * sdw_cdns_enable_interrupt() - Enable SDW interrupts and update config
>> @@ -839,7 +844,7 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
>>
>> cdns_writel(cdns, CDNS_MCP_INTMASK, mask);
>>
>> - return do_reset(cdns);
>> + return 0;
>> }
>> EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
>>
>> diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
>> index de97bc22acb7..2b551f9226f3 100644
>> --- a/drivers/soundwire/cadence_master.h
>> +++ b/drivers/soundwire/cadence_master.h
>> @@ -161,6 +161,7 @@ irqreturn_t sdw_cdns_thread(int irq, void *dev_id);
>> int sdw_cdns_init(struct sdw_cdns *cdns);
>> int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
>> struct sdw_cdns_stream_config config);
>> +int sdw_cdns_exit_reset(struct sdw_cdns *cdns);
>> int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
>>
>> void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
>> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
>> index a976480d6f36..9ebe38e4d979 100644
>> --- a/drivers/soundwire/intel.c
>> +++ b/drivers/soundwire/intel.c
>> @@ -1112,6 +1112,8 @@ static int intel_probe(struct platform_device *pdev)
>>
>> ret = sdw_cdns_enable_interrupt(&sdw->cdns);
>>
>> + ret = sdw_cdns_exit_reset(&sdw->cdns);
>> +
>> /* Register DAIs */
>> ret = intel_register_dai(sdw);
>> if (ret) {
>> @@ -1199,6 +1201,8 @@ static int intel_resume(struct device *dev)
>>
>> sdw_cdns_enable_interrupt(&sdw->cdns);
>>
>> + ret = sdw_cdns_exit_reset(&sdw->cdns);
>> +
>> return ret;
>> }
>>
>> --
>> 2.20.1
>

2019-08-03 16:41:27

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 34/40] soundwire: intel: ignore disabled links for suspend/resume

On 8/2/19 12:30 PM, Vinod Koul wrote:
> On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
>
> Please add explanation why..

yes missed this

>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/intel.c | 12 ++++++++++++
>> 1 file changed, 12 insertions(+)
>>
>> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
>> index 1477c35f616f..a976480d6f36 100644
>> --- a/drivers/soundwire/intel.c
>> +++ b/drivers/soundwire/intel.c
>> @@ -1161,6 +1161,12 @@ static int intel_suspend(struct device *dev)
>>
>> sdw = dev_get_drvdata(dev);
>>
>> + if (sdw->cdns.bus.prop.hw_disabled) {
>> + dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
>> + sdw->cdns.bus.link_id);
>> + return 0;
>> + }
>> +
>> ret = intel_link_power_down(sdw);
>> if (ret) {
>> dev_err(dev, "Link power down failed: %d", ret);
>> @@ -1179,6 +1185,12 @@ static int intel_resume(struct device *dev)
>>
>> sdw = dev_get_drvdata(dev);
>>
>> + if (sdw->cdns.bus.prop.hw_disabled) {
>> + dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n",
>> + sdw->cdns.bus.link_id);
>> + return 0;
>> + }
>> +
>> ret = intel_init(sdw);
>> if (ret) {
>> dev_err(dev, "%s failed: %d", __func__, ret);
>> --
>> 2.20.1
>

2019-08-03 16:41:28

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 31/40] soundwire: intel: move shutdown() callback and don't export symbol

On 8/2/19 12:28 PM, Vinod Koul wrote:
> On 26-07-19, 09:46, Pierre-Louis Bossart wrote:
>>
>>
>> On 7/26/19 5:38 AM, Cezary Rojewski wrote:
>>> On 2019-07-26 01:40, Pierre-Louis Bossart wrote:
>>>> +void intel_shutdown(struct snd_pcm_substream *substream,
>>>> +            struct snd_soc_dai *dai)
>>>> +{
>>>> +    struct sdw_cdns_dma_data *dma;
>>>> +
>>>> +    dma = snd_soc_dai_get_dma_data(dai, substream);
>>>> +    if (!dma)
>>>> +        return;
>>>> +
>>>> +    snd_soc_dai_set_dma_data(dai, substream, NULL);
>>>> +    kfree(dma);
>>>> +}
>>>
>>> Correct me if I'm wrong, but do we really need to _get_dma_ here?
>>> _set_dma_ seems bulletproof, same for kfree.
>>
>> I must admit I have no idea why we have a reference to DMAs here, this looks
>> like an abuse to store a dai-specific context, and the initial test looks
>> like copy-paste to detect invalid configs, as done in other callbacks. Vinod
>> and Sanyog might have more history than me here.
>
> I dont see snd_soc_dai_set_dma_data() call for
> sdw_cdns_dma_data so somthing is missing (at least in upstream code)
>
> IIRC we should have a snd_soc_dai_set_dma_data() in alloc or some
> initialization routine and we free it here.. Sanyog?

the code does a bunch of get_dma_data() and this seems to work, but
indeed I don't see where the _set_dma_data() is done. magic.

2019-08-04 00:32:32

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 20/40] soundwire: prototypes for suspend/resume

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:

Please do provide the changelog on why this change is needed.

> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.h | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
> index c0bf6ff00a44..d375bbfead18 100644
> --- a/drivers/soundwire/cadence_master.h
> +++ b/drivers/soundwire/cadence_master.h
> @@ -165,6 +165,9 @@ int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
>
> void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
>
> +int sdw_cdns_suspend(struct sdw_cdns *cdns);
> +bool sdw_cdns_check_resume_status(struct sdw_cdns *cdns);
> +
> int sdw_cdns_get_stream(struct sdw_cdns *cdns,
> struct sdw_cdns_streams *stream,
> u32 ch, u32 dir);
> --
> 2.20.1

--
~Vinod

2019-08-04 00:32:32

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 19/40] soundwire: bus: improve dynamic debug comments for enumeration

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
> update comments to provide better understanding of enumeration flows.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/bus.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
> index bca378806d00..2354675ef104 100644
> --- a/drivers/soundwire/bus.c
> +++ b/drivers/soundwire/bus.c
> @@ -483,7 +483,8 @@ static int sdw_assign_device_num(struct sdw_slave *slave)
>
> ret = sdw_write(slave, SDW_SCP_DEVNUMBER, dev_num);
> if (ret < 0) {
> - dev_err(&slave->dev, "Program device_num failed: %d\n", ret);
> + dev_err(&slave->dev, "Program device_num %d failed: %d\n",
> + dev_num, ret);
> return ret;
> }
>
> @@ -540,6 +541,7 @@ static int sdw_program_device_num(struct sdw_bus *bus)
> do {
> ret = sdw_transfer(bus, &msg);
> if (ret == -ENODATA) { /* end of device id reads */
> + dev_dbg(bus->dev, "No more devices to enumerate\n");
> ret = 0;
> break;
> }
> @@ -982,6 +984,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
> int i, ret = 0;
>
> if (status[0] == SDW_SLAVE_ATTACHED) {
> + dev_err(bus->dev, "Slave attached, programming device number\n");

This should be debug level

--
~Vinod

2019-08-04 00:34:22

by Vinod Koul

[permalink] [raw]
Subject: Re: [RFC PATCH 24/40] soundwire: cadence_master: use BIOS defaults for frame shape

On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
> Remove hard-coding and use BIOS values. If they are wrong use default

BIOS :) this is cadence, am sure this can be used outside BIOS :D

It would be better to say firmware (ACPI/DT)

> 48x2 frame shape.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 19 +++++++++++++++++--
> 1 file changed, 17 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 442f78c00f09..d84344e29f71 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -175,7 +175,6 @@
> /* Driver defaults */
>
> #define CDNS_DEFAULT_CLK_DIVIDER 0
> -#define CDNS_DEFAULT_FRAME_SHAPE 0x30
> #define CDNS_DEFAULT_SSP_INTERVAL 0x18
> #define CDNS_TX_TIMEOUT 2000
>
> @@ -954,6 +953,20 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
> }
> EXPORT_SYMBOL(sdw_cdns_pdi_init);
>
> +static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
> +{
> + u32 val;
> + int c;
> + int r;

This can be in single line!

> +
> + r = sdw_find_row_index(n_rows);
> + c = sdw_find_col_index(n_cols);
> +
> + val = (r << 3) | c;

Magic 3?

--
~Vinod

2019-08-04 01:05:54

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [RFC PATCH 19/40] soundwire: bus: improve dynamic debug comments for enumeration

On 8/2/19 12:00 PM, Vinod Koul wrote:
> On 25-07-19, 18:40, Pierre-Louis Bossart wrote:
>> update comments to provide better understanding of enumeration flows.
>>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/bus.c | 5 ++++-
>> 1 file changed, 4 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c
>> index bca378806d00..2354675ef104 100644
>> --- a/drivers/soundwire/bus.c
>> +++ b/drivers/soundwire/bus.c
>> @@ -483,7 +483,8 @@ static int sdw_assign_device_num(struct sdw_slave *slave)
>>
>> ret = sdw_write(slave, SDW_SCP_DEVNUMBER, dev_num);
>> if (ret < 0) {
>> - dev_err(&slave->dev, "Program device_num failed: %d\n", ret);
>> + dev_err(&slave->dev, "Program device_num %d failed: %d\n",
>> + dev_num, ret);
>> return ret;
>> }
>>
>> @@ -540,6 +541,7 @@ static int sdw_program_device_num(struct sdw_bus *bus)
>> do {
>> ret = sdw_transfer(bus, &msg);
>> if (ret == -ENODATA) { /* end of device id reads */
>> + dev_dbg(bus->dev, "No more devices to enumerate\n");
>> ret = 0;
>> break;
>> }
>> @@ -982,6 +984,7 @@ int sdw_handle_slave_status(struct sdw_bus *bus,
>> int i, ret = 0;
>>
>> if (status[0] == SDW_SLAVE_ATTACHED) {
>> + dev_err(bus->dev, "Slave attached, programming device number\n");
>
> This should be debug level

yes, good catch, will fix.

2019-08-05 07:54:12

by Sanyog Kale

[permalink] [raw]
Subject: Re: [RFC PATCH 02/40] soundwire: cadence_master: add debugfs register dump

On Thu, Jul 25, 2019 at 06:39:54PM -0500, Pierre-Louis Bossart wrote:
> Add debugfs file to dump the Cadence master registers
>
> Credits: this patch is based on an earlier internal contribution by
> Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. The main change
> is the use of scnprintf to avoid known issues with snprintf.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 98 ++++++++++++++++++++++++++++++
> drivers/soundwire/cadence_master.h | 2 +
> 2 files changed, 100 insertions(+)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index ff4badc9b3de..91e8bacb83e3 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -8,6 +8,7 @@
>
> #include <linux/delay.h>
> #include <linux/device.h>
> +#include <linux/debugfs.h>
> #include <linux/interrupt.h>
> #include <linux/io.h>
> #include <linux/module.h>
> @@ -223,6 +224,103 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value)
> return -EAGAIN;
> }
>
> +/*
> + * debugfs
> + */
> +
> +#define RD_BUF (2 * PAGE_SIZE)
> +
> +static ssize_t cdns_sprintf(struct sdw_cdns *cdns,
> + char *buf, size_t pos, unsigned int reg)
> +{
> + return scnprintf(buf + pos, RD_BUF - pos,
> + "%4x\t%4x\n", reg, cdns_readl(cdns, reg));
> +}
> +
> +static ssize_t cdns_reg_read(struct file *file, char __user *user_buf,
> + size_t count, loff_t *ppos)
> +{
> + struct sdw_cdns *cdns = file->private_data;
> + char *buf;
> + ssize_t ret;
> + int i, j;
> +
> + buf = kzalloc(RD_BUF, GFP_KERNEL);
> + if (!buf)
> + return -ENOMEM;
> +
> + ret = scnprintf(buf, RD_BUF, "Register Value\n");
> + ret += scnprintf(buf + ret, RD_BUF - ret, "\nMCP Registers\n");
> + for (i = 0; i < 8; i++) /* 8 MCP registers */
> + ret += cdns_sprintf(cdns, buf, ret, i * 4);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nStatus & Intr Registers\n");
> + for (i = 0; i < 13; i++) /* 13 Status & Intr registers */
> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_STAT + i * 4);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nSSP & Clk ctrl Registers\n");
> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL0);
> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL1);
> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL0);
> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL1);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nDPn B0 Registers\n");
> + for (i = 0; i < 7; i++) {
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nDP-%d\n", i);
> + for (j = 0; j < 6; j++)
> + ret += cdns_sprintf(cdns, buf, ret,
> + CDNS_DPN_B0_CONFIG(i) + j * 4);
> + }
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nDPn B1 Registers\n");
> + for (i = 0; i < 7; i++) {
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nDP-%d\n", i);
> +
> + for (j = 0; j < 6; j++)
> + ret += cdns_sprintf(cdns, buf, ret,
> + CDNS_DPN_B1_CONFIG(i) + j * 4);
> + }
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nDPn Control Registers\n");
> + for (i = 0; i < 7; i++)
> + ret += cdns_sprintf(cdns, buf, ret,
> + CDNS_PORTCTRL + i * CDNS_PORT_OFFSET);
> +
> + ret += scnprintf(buf + ret, RD_BUF - ret,
> + "\nPDIn Config Registers\n");
> + for (i = 0; i < 7; i++)

please use macros for all the hardcodings.

> + ret += cdns_sprintf(cdns, buf, ret, CDNS_PDI_CONFIG(i));
> +
> + ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
> + kfree(buf);
> +
> + return ret;
> +}
> +
> +static const struct file_operations cdns_reg_fops = {
> + .open = simple_open,
> + .read = cdns_reg_read,
> + .llseek = default_llseek,
> +};
> +
> +/**
> + * sdw_cdns_debugfs_init() - Cadence debugfs init
> + * @cdns: Cadence instance
> + * @root: debugfs root
> + */
> +void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root)
> +{
> + debugfs_create_file("cdns-registers", 0400, root, cdns, &cdns_reg_fops);
> +}
> +EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init);
> +
> /*
> * IO Calls
> */
> diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h
> index fe2af62958b1..c0bf6ff00a44 100644
> --- a/drivers/soundwire/cadence_master.h
> +++ b/drivers/soundwire/cadence_master.h
> @@ -163,6 +163,8 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
> struct sdw_cdns_stream_config config);
> int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns);
>
> +void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root);
> +
> int sdw_cdns_get_stream(struct sdw_cdns *cdns,
> struct sdw_cdns_streams *stream,
> u32 ch, u32 dir);
> --
> 2.20.1
>

--

2019-08-05 08:51:41

by Sanyog Kale

[permalink] [raw]
Subject: Re: [RFC PATCH 09/40] soundwire: cadence_master: fix usage of CONFIG_UPDATE

On Thu, Jul 25, 2019 at 06:40:01PM -0500, Pierre-Louis Bossart wrote:
> Per the hardware documentation, all changes to MCP_CONFIG,
> MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL need to be validated with a
> self-clearing write to MCP_CONFIG_UPDATE.
>
> For some reason, the existing code only does this write to
> CONFIG_UPDATE when enabling interrupts. Add a helper and do the update
> when the CONFIG is changed.
>

the sequence of intel_probe is as follows:
1. intel_link_power_up
2. intel_shim_init
3. sdw_cdns_init
4. sdw_cdns_enable_interrupt

Since we do self-clearing write to MCP_CONFIG_UPDATE in
sdw_cdns_enable_interrupt once for all the config changes,
we dont perform it as part of sdw_cdns_init.

It does make sense to seperate it out from sdw_cdns_enable_interrupt so
that we can use when clockstop is enabled where we dont need to enable
interrupts.

> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 29 +++++++++++++++++++++--------
> 1 file changed, 21 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 9f611a1fff0a..eb46cf651d62 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -224,6 +224,22 @@ static int cdns_clear_bit(struct sdw_cdns *cdns, int offset, u32 value)
> return -EAGAIN;
> }
>
> +/*
> + * all changes to the MCP_CONFIG, MCP_CONTROL, MCP_CMDCTRL and MCP_PHYCTRL
> + * need to be confirmed with a write to MCP_CONFIG_UPDATE
> + */
> +static int cdns_update_config(struct sdw_cdns *cdns)
> +{
> + int ret;
> +
> + ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
> + CDNS_MCP_CONFIG_UPDATE_BIT);
> + if (ret < 0)
> + dev_err(cdns->dev, "Config update timedout\n");
> +
> + return ret;
> +}
> +
> /*
> * debugfs
> */
> @@ -758,15 +774,9 @@ static int _cdns_enable_interrupt(struct sdw_cdns *cdns)
> */
> int sdw_cdns_enable_interrupt(struct sdw_cdns *cdns)
> {
> - int ret;
> -
> _cdns_enable_interrupt(cdns);
> - ret = cdns_clear_bit(cdns, CDNS_MCP_CONFIG_UPDATE,
> - CDNS_MCP_CONFIG_UPDATE_BIT);
> - if (ret < 0)
> - dev_err(cdns->dev, "Config update timedout\n");
>
> - return ret;
> + return 0;
> }
> EXPORT_SYMBOL(sdw_cdns_enable_interrupt);
>
> @@ -943,7 +953,10 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
>
> cdns_writel(cdns, CDNS_MCP_CONFIG, val);
>
> - return 0;
> + /* commit changes */
> + ret = cdns_update_config(cdns);
> +
> + return ret;
> }
> EXPORT_SYMBOL(sdw_cdns_init);
>
> --
> 2.20.1
>

--

2019-08-05 09:40:08

by Sanyog Kale

[permalink] [raw]
Subject: Re: [RFC PATCH 21/40] soundwire: export helpers to find row and column values

On Thu, Jul 25, 2019 at 06:40:13PM -0500, Pierre-Louis Bossart wrote:
> Add a prefix for common tables and export 2 helpers to set the frame
> shapes based on row/col values.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/bus.h | 7 +++++--
> drivers/soundwire/stream.c | 14 ++++++++------
> 2 files changed, 13 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
> index 06ac4adb0074..c57c9c23f6ca 100644
> --- a/drivers/soundwire/bus.h
> +++ b/drivers/soundwire/bus.h
> @@ -73,8 +73,11 @@ struct sdw_msg {
>
> #define SDW_DOUBLE_RATE_FACTOR 2
>
> -extern int rows[SDW_FRAME_ROWS];
> -extern int cols[SDW_FRAME_COLS];
> +extern int sdw_rows[SDW_FRAME_ROWS];
> +extern int sdw_cols[SDW_FRAME_COLS];
> +
> +int sdw_find_row_index(int row);
> +int sdw_find_col_index(int col);

We use index values only in bank switch operations to program registers. Do we
really need to export sdw_find_row_index & sdw_find_col_index?? If i understand
correctly the allocation algorithm only needs to know about cols and rows values
and not index.

>
> /**
> * sdw_port_runtime: Runtime port parameters for Master or Slave
> diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
> index a0476755a459..53f5e790fcd7 100644
> --- a/drivers/soundwire/stream.c
> +++ b/drivers/soundwire/stream.c
> @@ -21,37 +21,39 @@
> * The rows are arranged as per the array index value programmed
> * in register. The index 15 has dummy value 0 in order to fill hole.
> */
> -int rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,
> +int sdw_rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,
> 96, 100, 120, 128, 150, 160, 250, 0,
> 192, 200, 240, 256, 72, 144, 90, 180};
>
> -int cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};
> +int sdw_cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};
>
> -static int sdw_find_col_index(int col)
> +int sdw_find_col_index(int col)
> {
> int i;
>
> for (i = 0; i < SDW_FRAME_COLS; i++) {
> - if (cols[i] == col)
> + if (sdw_cols[i] == col)
> return i;
> }
>
> pr_warn("Requested column not found, selecting lowest column no: 2\n");
> return 0;
> }
> +EXPORT_SYMBOL(sdw_find_col_index);
>
> -static int sdw_find_row_index(int row)
> +int sdw_find_row_index(int row)
> {
> int i;
>
> for (i = 0; i < SDW_FRAME_ROWS; i++) {
> - if (rows[i] == row)
> + if (sdw_rows[i] == row)
> return i;
> }
>
> pr_warn("Requested row not found, selecting lowest row no: 48\n");
> return 0;
> }
> +EXPORT_SYMBOL(sdw_find_row_index);
>
> static int _sdw_program_slave_port_params(struct sdw_bus *bus,
> struct sdw_slave *slave,
> --
> 2.20.1
>

--

2019-08-05 09:56:51

by Sanyog Kale

[permalink] [raw]
Subject: Re: [RFC PATCH 23/40] soundwire: stream: fix disable sequence

On Thu, Jul 25, 2019 at 06:40:15PM -0500, Pierre-Louis Bossart wrote:
> When we disable the stream and then call hw_free, two bank switches
> will be handled and as a result we re-enable the stream on hw_free.
>

I didnt quite get why there will be two bank switches as part of disable flow
which leads to enabling of stream?

> Make sure the stream is disabled on both banks.
>
> TODO: we need to completely revisit all this and make sure we have a
> mirroring mechanism between current and alternate banks.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/stream.c | 19 ++++++++++++++++++-
> 1 file changed, 18 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
> index 53f5e790fcd7..75b9ad1fb1a6 100644
> --- a/drivers/soundwire/stream.c
> +++ b/drivers/soundwire/stream.c
> @@ -1637,7 +1637,24 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
> }
> }
>
> - return do_bank_switch(stream);
> + ret = do_bank_switch(stream);
> + if (ret < 0) {
> + dev_err(bus->dev, "Bank switch failed: %d\n", ret);
> + return ret;
> + }
> +
> + /* make sure alternate bank (previous current) is also disabled */
> + list_for_each_entry(m_rt, &stream->master_list, stream_node) {
> + bus = m_rt->bus;
> + /* Disable port(s) */
> + ret = sdw_enable_disable_ports(m_rt, false);
> + if (ret < 0) {
> + dev_err(bus->dev, "Disable port(s) failed: %d\n", ret);
> + return ret;
> + }
> + }
> +
> + return 0;
> }
>
> /**
> --
> 2.20.1
>

--

2019-08-05 10:00:20

by Sanyog Kale

[permalink] [raw]
Subject: Re: [RFC PATCH 24/40] soundwire: cadence_master: use BIOS defaults for frame shape

On Thu, Jul 25, 2019 at 06:40:16PM -0500, Pierre-Louis Bossart wrote:
> Remove hard-coding and use BIOS values. If they are wrong use default
> 48x2 frame shape.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 19 +++++++++++++++++--
> 1 file changed, 17 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 442f78c00f09..d84344e29f71 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -175,7 +175,6 @@
> /* Driver defaults */
>
> #define CDNS_DEFAULT_CLK_DIVIDER 0
> -#define CDNS_DEFAULT_FRAME_SHAPE 0x30
> #define CDNS_DEFAULT_SSP_INTERVAL 0x18
> #define CDNS_TX_TIMEOUT 2000
>
> @@ -954,6 +953,20 @@ int sdw_cdns_pdi_init(struct sdw_cdns *cdns,
> }
> EXPORT_SYMBOL(sdw_cdns_pdi_init);
>
> +static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
> +{
> + u32 val;
> + int c;
> + int r;
> +
> + r = sdw_find_row_index(n_rows);
> + c = sdw_find_col_index(n_cols);
> +

Now i get why you need above functions to be exported, please ignore my
previous comment.

> + val = (r << 3) | c;
> +
> + return val;
> +}
> +
> /**
> * sdw_cdns_init() - Cadence initialization
> * @cdns: Cadence instance
> @@ -977,7 +990,9 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
> cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
>
> /* Set the default frame shape */
> - cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT, CDNS_DEFAULT_FRAME_SHAPE);
> + val = cdns_set_default_frame_shape(prop->default_row,
> + prop->default_col);
> + cdns_writel(cdns, CDNS_MCP_FRAME_SHAPE_INIT, val);
>
> /* Set SSP interval to default value */
> cdns_writel(cdns, CDNS_MCP_SSP_CTRL0, CDNS_DEFAULT_SSP_INTERVAL);
> --
> 2.20.1
>

--

2019-08-05 10:28:14

by Sanyog Kale

[permalink] [raw]
Subject: Re: [RFC PATCH 25/40] soundwire: intel: use BIOS information to set clock dividers

On Thu, Jul 25, 2019 at 06:40:17PM -0500, Pierre-Louis Bossart wrote:
> The BIOS provides an Intel-specific property, let's use it to avoid
> hard-coded clock dividers.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 26 ++++++++++++++++++++++----
> drivers/soundwire/intel.c | 26 ++++++++++++++++++++++++++
> include/linux/soundwire/sdw.h | 2 ++
> 3 files changed, 50 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index d84344e29f71..10ebcef2e84e 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -173,8 +173,6 @@
> #define CDNS_PDI_CONFIG_PORT GENMASK(4, 0)
>
> /* Driver defaults */
> -
> -#define CDNS_DEFAULT_CLK_DIVIDER 0
> #define CDNS_DEFAULT_SSP_INTERVAL 0x18
> #define CDNS_TX_TIMEOUT 2000
>
> @@ -973,7 +971,10 @@ static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
> */
> int sdw_cdns_init(struct sdw_cdns *cdns)
> {
> + struct sdw_bus *bus = &cdns->bus;
> + struct sdw_master_prop *prop = &bus->prop;
> u32 val;
> + int divider;
> int ret;
>
> /* Exit clock stop */
> @@ -985,9 +986,17 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
> }
>
> /* Set clock divider */
> + divider = (prop->mclk_freq / prop->max_clk_freq) - 1;

Do you expect mclk_freq and max_clk_freq to be same?

> val = cdns_readl(cdns, CDNS_MCP_CLK_CTRL0);
> - val |= CDNS_DEFAULT_CLK_DIVIDER;
> + val |= divider;
> cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
> + cdns_writel(cdns, CDNS_MCP_CLK_CTRL1, val);
> +
> + pr_err("plb: mclk %d max_freq %d divider %d register %x\n",
> + prop->mclk_freq,
> + prop->max_clk_freq,
> + divider,
> + val);

This can be removed.

>
> /* Set the default frame shape */
> val = cdns_set_default_frame_shape(prop->default_row,
> @@ -1035,6 +1044,7 @@ EXPORT_SYMBOL(sdw_cdns_init);
>
> int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
> {
> + struct sdw_master_prop *prop = &bus->prop;
> struct sdw_cdns *cdns = bus_to_cdns(bus);
> int mcp_clkctrl_off, mcp_clkctrl;
> int divider;
> @@ -1044,7 +1054,9 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
> return -EINVAL;
> }
>
> - divider = (params->max_dr_freq / params->curr_dr_freq) - 1;
> + divider = prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR /

What is the reason for not using max_dr_freq? Its precomputed as
prop->max_clk_freq * SDW_DOUBLE_RATE_FACTOR;

> + params->curr_dr_freq;
> + divider--; /* divider is 1/(N+1) */
>
> if (params->next_bank)
> mcp_clkctrl_off = CDNS_MCP_CLK_CTRL1;
> @@ -1055,6 +1067,12 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
> mcp_clkctrl |= divider;
> cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl);
>
> + pr_err("plb: mclk * 2 %d curr_dr_freq %d divider %d register %x\n",
> + prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR,
> + params->curr_dr_freq,
> + divider,
> + mcp_clkctrl);
> +
> return 0;
> }
> EXPORT_SYMBOL(cdns_bus_conf);
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index c718c9c67a37..796ac2bc8cea 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -917,11 +917,37 @@ static int intel_register_dai(struct sdw_intel *sdw)
> dais, num_dai);
> }
>
> +static int sdw_master_read_intel_prop(struct sdw_bus *bus)
> +{
> + struct sdw_master_prop *prop = &bus->prop;
> + struct fwnode_handle *link;
> + char name[32];
> + int nval, i;
> +
> + /* Find master handle */
> + snprintf(name, sizeof(name),
> + "mipi-sdw-link-%d-subproperties", bus->link_id);
> +
> + link = device_get_named_child_node(bus->dev, name);
> + if (!link) {
> + dev_err(bus->dev, "Master node %s not found\n", name);
> + return -EIO;
> + }
> +
> + fwnode_property_read_u32(link,
> + "intel-sdw-ip-clock",
> + &prop->mclk_freq);
> + return 0;
> +}
> +
> static int intel_prop_read(struct sdw_bus *bus)
> {
> /* Initialize with default handler to read all DisCo properties */
> sdw_master_read_prop(bus);
>
> + /* read Intel-specific properties */
> + sdw_master_read_intel_prop(bus);
> +
> return 0;
> }
>
> diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
> index 31d1e8acf25b..b6acc436ac80 100644
> --- a/include/linux/soundwire/sdw.h
> +++ b/include/linux/soundwire/sdw.h
> @@ -379,6 +379,7 @@ struct sdw_slave_prop {
> * @dynamic_frame: Dynamic frame shape supported
> * @err_threshold: Number of times that software may retry sending a single
> * command
> + * @mclk_freq: clock reference passed to SoundWire Master, in Hz.
> */
> struct sdw_master_prop {
> u32 revision;
> @@ -393,6 +394,7 @@ struct sdw_master_prop {
> u32 default_col;
> bool dynamic_frame;
> u32 err_threshold;
> + u32 mclk_freq;
> };
>
> int sdw_master_read_prop(struct sdw_bus *bus);
> --
> 2.20.1
>

--

2019-08-05 10:41:43

by Sanyog Kale

[permalink] [raw]
Subject: Re: [RFC PATCH 26/40] soundwire: cadence_master: fix divider setting in clock register

On Thu, Jul 25, 2019 at 06:40:18PM -0500, Pierre-Louis Bossart wrote:
> From: Rander Wang <[email protected]>
>
> The existing code uses an OR operation which would mix the original
> divider setting with the new one, resulting in an invalid
> configuration that can make codecs hang.
>
> Add the mask definition and use cdns_updatel to update divider
>
> Signed-off-by: Rander Wang <[email protected]>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/cadence_master.c | 12 +++++++-----
> 1 file changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
> index 10ebcef2e84e..18c6ac026e85 100644
> --- a/drivers/soundwire/cadence_master.c
> +++ b/drivers/soundwire/cadence_master.c
> @@ -57,6 +57,7 @@
> #define CDNS_MCP_SSP_CTRL1 0x28
> #define CDNS_MCP_CLK_CTRL0 0x30
> #define CDNS_MCP_CLK_CTRL1 0x38
> +#define CDNS_MCP_CLK_MCLKD_MASK GENMASK(7, 0)
>
> #define CDNS_MCP_STAT 0x40
>
> @@ -988,9 +989,11 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
> /* Set clock divider */
> divider = (prop->mclk_freq / prop->max_clk_freq) - 1;
> val = cdns_readl(cdns, CDNS_MCP_CLK_CTRL0);

reg read of CLK_CTRL0 can be removed.

> - val |= divider;
> - cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
> - cdns_writel(cdns, CDNS_MCP_CLK_CTRL1, val);
> +
> + cdns_updatel(cdns, CDNS_MCP_CLK_CTRL0,
> + CDNS_MCP_CLK_MCLKD_MASK, divider);
> + cdns_updatel(cdns, CDNS_MCP_CLK_CTRL1,
> + CDNS_MCP_CLK_MCLKD_MASK, divider);
>
> pr_err("plb: mclk %d max_freq %d divider %d register %x\n",
> prop->mclk_freq,
> @@ -1064,8 +1067,7 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
> mcp_clkctrl_off = CDNS_MCP_CLK_CTRL0;
>
> mcp_clkctrl = cdns_readl(cdns, mcp_clkctrl_off);

same as above.

> - mcp_clkctrl |= divider;
> - cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl);
> + cdns_updatel(cdns, mcp_clkctrl_off, CDNS_MCP_CLK_MCLKD_MASK, divider);
>
> pr_err("plb: mclk * 2 %d curr_dr_freq %d divider %d register %x\n",
> prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR,
> --
> 2.20.1
>

--

2019-08-05 15:21:38

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 02/40] soundwire: cadence_master: add debugfs register dump


>> +static ssize_t cdns_reg_read(struct file *file, char __user *user_buf,
>> + size_t count, loff_t *ppos)
>> +{
>> + struct sdw_cdns *cdns = file->private_data;
>> + char *buf;
>> + ssize_t ret;
>> + int i, j;
>> +
>> + buf = kzalloc(RD_BUF, GFP_KERNEL);
>> + if (!buf)
>> + return -ENOMEM;
>> +
>> + ret = scnprintf(buf, RD_BUF, "Register Value\n");
>> + ret += scnprintf(buf + ret, RD_BUF - ret, "\nMCP Registers\n");
>> + for (i = 0; i < 8; i++) /* 8 MCP registers */
>> + ret += cdns_sprintf(cdns, buf, ret, i * 4);
>> +
>> + ret += scnprintf(buf + ret, RD_BUF - ret,
>> + "\nStatus & Intr Registers\n");
>> + for (i = 0; i < 13; i++) /* 13 Status & Intr registers */
>> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_STAT + i * 4);
>> +
>> + ret += scnprintf(buf + ret, RD_BUF - ret,
>> + "\nSSP & Clk ctrl Registers\n");
>> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL0);
>> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_SSP_CTRL1);
>> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL0);
>> + ret += cdns_sprintf(cdns, buf, ret, CDNS_MCP_CLK_CTRL1);
>> +
>> + ret += scnprintf(buf + ret, RD_BUF - ret,
>> + "\nDPn B0 Registers\n");
>> + for (i = 0; i < 7; i++) {
>> + ret += scnprintf(buf + ret, RD_BUF - ret,
>> + "\nDP-%d\n", i);
>> + for (j = 0; j < 6; j++)
>> + ret += cdns_sprintf(cdns, buf, ret,
>> + CDNS_DPN_B0_CONFIG(i) + j * 4);
>> + }
>> +
>> + ret += scnprintf(buf + ret, RD_BUF - ret,
>> + "\nDPn B1 Registers\n");
>> + for (i = 0; i < 7; i++) {
>> + ret += scnprintf(buf + ret, RD_BUF - ret,
>> + "\nDP-%d\n", i);
>> +
>> + for (j = 0; j < 6; j++)
>> + ret += cdns_sprintf(cdns, buf, ret,
>> + CDNS_DPN_B1_CONFIG(i) + j * 4);
>> + }
>> +
>> + ret += scnprintf(buf + ret, RD_BUF - ret,
>> + "\nDPn Control Registers\n");
>> + for (i = 0; i < 7; i++)
>> + ret += cdns_sprintf(cdns, buf, ret,
>> + CDNS_PORTCTRL + i * CDNS_PORT_OFFSET);
>> +
>> + ret += scnprintf(buf + ret, RD_BUF - ret,
>> + "\nPDIn Config Registers\n");
>> + for (i = 0; i < 7; i++)
>
> please use macros for all the hardcodings.

yes, I completely changed that part in the upcoming update by using
register start/stop for all loops, it makes the code more consistent and
easier to change (SoundWire 1.2 registers will need to be added)

2019-08-05 15:31:36

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 21/40] soundwire: export helpers to find row and column values



On 8/5/19 4:39 AM, Sanyog Kale wrote:
> On Thu, Jul 25, 2019 at 06:40:13PM -0500, Pierre-Louis Bossart wrote:
>> Add a prefix for common tables and export 2 helpers to set the frame
>> shapes based on row/col values.
>>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/bus.h | 7 +++++--
>> drivers/soundwire/stream.c | 14 ++++++++------
>> 2 files changed, 13 insertions(+), 8 deletions(-)
>>
>> diff --git a/drivers/soundwire/bus.h b/drivers/soundwire/bus.h
>> index 06ac4adb0074..c57c9c23f6ca 100644
>> --- a/drivers/soundwire/bus.h
>> +++ b/drivers/soundwire/bus.h
>> @@ -73,8 +73,11 @@ struct sdw_msg {
>>
>> #define SDW_DOUBLE_RATE_FACTOR 2
>>
>> -extern int rows[SDW_FRAME_ROWS];
>> -extern int cols[SDW_FRAME_COLS];
>> +extern int sdw_rows[SDW_FRAME_ROWS];
>> +extern int sdw_cols[SDW_FRAME_COLS];
>> +
>> +int sdw_find_row_index(int row);
>> +int sdw_find_col_index(int col);
>
> We use index values only in bank switch operations to program registers. Do we
> really need to export sdw_find_row_index & sdw_find_col_index?? If i understand
> correctly the allocation algorithm only needs to know about cols and rows values
> and not index.

The allocation does work with cols and rows indeed, but will first run
the code below where the information f is required:

static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq)
{
struct sdw_master_prop *prop = &bus->prop;
int frame_int, frame_freq;
int r, c;

for (c = 0; c < SDW_FRAME_COLS; c++) {
for (r = 0; r < SDW_FRAME_ROWS; r++) {
if (sdw_rows[r] != prop->default_row ||
sdw_cols[c] != prop->default_col)
continue;

frame_int = sdw_rows[r] * sdw_cols[c];
frame_freq = clk_freq / frame_int;

if ((clk_freq - (frame_freq * SDW_FRAME_CTRL_BITS)) <
bus->params.bandwidth)
continue;

bus->params.row = sdw_rows[r];
bus->params.col = sdw_cols[c];
return 0;
}
}

return -EINVAL;
}

as for the two helpers, they are used in both the allocation and the
cadence code (to determine the initial frame shape from properties).

And other solutions for non-Intel platforms will also need this to
convert from indices to frame shape.

So yes all of this is needed.


>
>>
>> /**
>> * sdw_port_runtime: Runtime port parameters for Master or Slave
>> diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
>> index a0476755a459..53f5e790fcd7 100644
>> --- a/drivers/soundwire/stream.c
>> +++ b/drivers/soundwire/stream.c
>> @@ -21,37 +21,39 @@
>> * The rows are arranged as per the array index value programmed
>> * in register. The index 15 has dummy value 0 in order to fill hole.
>> */
>> -int rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,
>> +int sdw_rows[SDW_FRAME_ROWS] = {48, 50, 60, 64, 75, 80, 125, 147,
>> 96, 100, 120, 128, 150, 160, 250, 0,
>> 192, 200, 240, 256, 72, 144, 90, 180};
>>
>> -int cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};
>> +int sdw_cols[SDW_FRAME_COLS] = {2, 4, 6, 8, 10, 12, 14, 16};
>>
>> -static int sdw_find_col_index(int col)
>> +int sdw_find_col_index(int col)
>> {
>> int i;
>>
>> for (i = 0; i < SDW_FRAME_COLS; i++) {
>> - if (cols[i] == col)
>> + if (sdw_cols[i] == col)
>> return i;
>> }
>>
>> pr_warn("Requested column not found, selecting lowest column no: 2\n");
>> return 0;
>> }
>> +EXPORT_SYMBOL(sdw_find_col_index);
>>
>> -static int sdw_find_row_index(int row)
>> +int sdw_find_row_index(int row)
>> {
>> int i;
>>
>> for (i = 0; i < SDW_FRAME_ROWS; i++) {
>> - if (rows[i] == row)
>> + if (sdw_rows[i] == row)
>> return i;
>> }
>>
>> pr_warn("Requested row not found, selecting lowest row no: 48\n");
>> return 0;
>> }
>> +EXPORT_SYMBOL(sdw_find_row_index);
>>
>> static int _sdw_program_slave_port_params(struct sdw_bus *bus,
>> struct sdw_slave *slave,
>> --
>> 2.20.1
>>
>

2019-08-05 15:34:24

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 23/40] soundwire: stream: fix disable sequence



On 8/5/19 4:56 AM, Sanyog Kale wrote:
> On Thu, Jul 25, 2019 at 06:40:15PM -0500, Pierre-Louis Bossart wrote:
>> When we disable the stream and then call hw_free, two bank switches
>> will be handled and as a result we re-enable the stream on hw_free.
>>
>
> I didnt quite get why there will be two bank switches as part of disable flow
> which leads to enabling of stream?

You have two bank switches, one to stop streaming and on in de-prepare.
It's symmetrical with the start sequence, where we do a bank switch to
prepare and another to enable.

Let's assume we are using bank0 when streaming.

Before the first bank switch, the channel_enable is set to false in the
alternate bank1. When the bank switch happens, bank1 become active and
the streaming stops. But bank0 registers have not been modified so when
we do the second bank switch in de-prepare we make bank0 active, and the
ch_enable bits are still set so streaming will restart... When we stop
streaming, we need to make sure the ch_enable bits are cleared in the
two banks.


>
>> Make sure the stream is disabled on both banks.
>>
>> TODO: we need to completely revisit all this and make sure we have a
>> mirroring mechanism between current and alternate banks.
>>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/stream.c | 19 ++++++++++++++++++-
>> 1 file changed, 18 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
>> index 53f5e790fcd7..75b9ad1fb1a6 100644
>> --- a/drivers/soundwire/stream.c
>> +++ b/drivers/soundwire/stream.c
>> @@ -1637,7 +1637,24 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
>> }
>> }
>>
>> - return do_bank_switch(stream);
>> + ret = do_bank_switch(stream);
>> + if (ret < 0) {
>> + dev_err(bus->dev, "Bank switch failed: %d\n", ret);
>> + return ret;
>> + }
>> +
>> + /* make sure alternate bank (previous current) is also disabled */
>> + list_for_each_entry(m_rt, &stream->master_list, stream_node) {
>> + bus = m_rt->bus;
>> + /* Disable port(s) */
>> + ret = sdw_enable_disable_ports(m_rt, false);
>> + if (ret < 0) {
>> + dev_err(bus->dev, "Disable port(s) failed: %d\n", ret);
>> + return ret;
>> + }
>> + }
>> +
>> + return 0;
>> }
>>
>> /**
>> --
>> 2.20.1
>>
>

2019-08-05 15:41:10

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 25/40] soundwire: intel: use BIOS information to set clock dividers



On 8/5/19 5:28 AM, Sanyog Kale wrote:
> On Thu, Jul 25, 2019 at 06:40:17PM -0500, Pierre-Louis Bossart wrote:
>> The BIOS provides an Intel-specific property, let's use it to avoid
>> hard-coded clock dividers.
>>
>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>> ---
>> drivers/soundwire/cadence_master.c | 26 ++++++++++++++++++++++----
>> drivers/soundwire/intel.c | 26 ++++++++++++++++++++++++++
>> include/linux/soundwire/sdw.h | 2 ++
>> 3 files changed, 50 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c
>> index d84344e29f71..10ebcef2e84e 100644
>> --- a/drivers/soundwire/cadence_master.c
>> +++ b/drivers/soundwire/cadence_master.c
>> @@ -173,8 +173,6 @@
>> #define CDNS_PDI_CONFIG_PORT GENMASK(4, 0)
>>
>> /* Driver defaults */
>> -
>> -#define CDNS_DEFAULT_CLK_DIVIDER 0
>> #define CDNS_DEFAULT_SSP_INTERVAL 0x18
>> #define CDNS_TX_TIMEOUT 2000
>>
>> @@ -973,7 +971,10 @@ static u32 cdns_set_default_frame_shape(int n_rows, int n_cols)
>> */
>> int sdw_cdns_init(struct sdw_cdns *cdns)
>> {
>> + struct sdw_bus *bus = &cdns->bus;
>> + struct sdw_master_prop *prop = &bus->prop;
>> u32 val;
>> + int divider;
>> int ret;
>>
>> /* Exit clock stop */
>> @@ -985,9 +986,17 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
>> }
>>
>> /* Set clock divider */
>> + divider = (prop->mclk_freq / prop->max_clk_freq) - 1;
>
> Do you expect mclk_freq and max_clk_freq to be same?

Nope. For Icelake the MCLK is 38.4 MHz and is, but the max_clk needs to
be 9.6 max (can't be higher per the SoundWire spec).

The max_clk_freq may even be lower thank 9.6 MHz due to specific
topologies where the higher frequencies are problematic if the trace
lengths are too long.

For CNL/CML the MCLK is 24 MHz but ironically we run the bus at 12 MHz,
so the divider is smaller.

>
>> val = cdns_readl(cdns, CDNS_MCP_CLK_CTRL0);
>> - val |= CDNS_DEFAULT_CLK_DIVIDER;
>> + val |= divider;
>> cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
>> + cdns_writel(cdns, CDNS_MCP_CLK_CTRL1, val);
>> +
>> + pr_err("plb: mclk %d max_freq %d divider %d register %x\n",
>> + prop->mclk_freq,
>> + prop->max_clk_freq,
>> + divider,
>> + val);
>
> This can be removed.

yes, done already.

>
>>
>> /* Set the default frame shape */
>> val = cdns_set_default_frame_shape(prop->default_row,
>> @@ -1035,6 +1044,7 @@ EXPORT_SYMBOL(sdw_cdns_init);
>>
>> int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
>> {
>> + struct sdw_master_prop *prop = &bus->prop;
>> struct sdw_cdns *cdns = bus_to_cdns(bus);
>> int mcp_clkctrl_off, mcp_clkctrl;
>> int divider;
>> @@ -1044,7 +1054,9 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
>> return -EINVAL;
>> }
>>
>> - divider = (params->max_dr_freq / params->curr_dr_freq) - 1;
>> + divider = prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR /
>
> What is the reason for not using max_dr_freq? Its precomputed as
> prop->max_clk_freq * SDW_DOUBLE_RATE_FACTOR;

no, as explained above the divider needs to start from the clock
provided to the IP, which is different from the max frequency clock the
bus operates at. the MCLK is a fixed value for all platforms using the
same SOC/PCH, the max_clk is platform-dependent and its value is
provided by the firmware (BIOS/DT).

2019-08-05 15:43:37

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 26/40] soundwire: cadence_master: fix divider setting in clock register


>> @@ -988,9 +989,11 @@ int sdw_cdns_init(struct sdw_cdns *cdns)
>> /* Set clock divider */
>> divider = (prop->mclk_freq / prop->max_clk_freq) - 1;
>> val = cdns_readl(cdns, CDNS_MCP_CLK_CTRL0);
>
> reg read of CLK_CTRL0 can be removed.

yes for both comments. Thanks for the review Sanyog, appreciate it.

>
>> - val |= divider;
>> - cdns_writel(cdns, CDNS_MCP_CLK_CTRL0, val);
>> - cdns_writel(cdns, CDNS_MCP_CLK_CTRL1, val);
>> +
>> + cdns_updatel(cdns, CDNS_MCP_CLK_CTRL0,
>> + CDNS_MCP_CLK_MCLKD_MASK, divider);
>> + cdns_updatel(cdns, CDNS_MCP_CLK_CTRL1,
>> + CDNS_MCP_CLK_MCLKD_MASK, divider);
>>
>> pr_err("plb: mclk %d max_freq %d divider %d register %x\n",
>> prop->mclk_freq,
>> @@ -1064,8 +1067,7 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params)
>> mcp_clkctrl_off = CDNS_MCP_CLK_CTRL0;
>>
>> mcp_clkctrl = cdns_readl(cdns, mcp_clkctrl_off);
>
> same as above.
>
>> - mcp_clkctrl |= divider;
>> - cdns_writel(cdns, mcp_clkctrl_off, mcp_clkctrl);
>> + cdns_updatel(cdns, mcp_clkctrl_off, CDNS_MCP_CLK_MCLKD_MASK, divider);
>>
>> pr_err("plb: mclk * 2 %d curr_dr_freq %d divider %d register %x\n",
>> prop->mclk_freq * SDW_DOUBLE_RATE_FACTOR,
>> --
>> 2.20.1
>>
>

2019-08-05 16:31:39

by Sanyog Kale

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 23/40] soundwire: stream: fix disable sequence

On Mon, Aug 05, 2019 at 10:33:25AM -0500, Pierre-Louis Bossart wrote:
>
>
> On 8/5/19 4:56 AM, Sanyog Kale wrote:
> > On Thu, Jul 25, 2019 at 06:40:15PM -0500, Pierre-Louis Bossart wrote:
> > > When we disable the stream and then call hw_free, two bank switches
> > > will be handled and as a result we re-enable the stream on hw_free.
> > >
> >
> > I didnt quite get why there will be two bank switches as part of disable flow
> > which leads to enabling of stream?
>
> You have two bank switches, one to stop streaming and on in de-prepare. It's
> symmetrical with the start sequence, where we do a bank switch to prepare
> and another to enable.

Got it. I misunderstood it that two bank switches are performed as part of
disable_stream.

>
> Let's assume we are using bank0 when streaming.
>
> Before the first bank switch, the channel_enable is set to false in the
> alternate bank1. When the bank switch happens, bank1 become active and the
> streaming stops. But bank0 registers have not been modified so when we do
> the second bank switch in de-prepare we make bank0 active, and the ch_enable
> bits are still set so streaming will restart... When we stop streaming, we
> need to make sure the ch_enable bits are cleared in the two banks.

This is clear. Even though the channels remains enabled, i believe there
won't be any data pushed on lines as stream will be closed.

Regarding mirroring approach, I assume after bank switch we will take
snapshot of active bank and program same in inactive bank.

>
>
> >
> > > Make sure the stream is disabled on both banks.
> > >
> > > TODO: we need to completely revisit all this and make sure we have a
> > > mirroring mechanism between current and alternate banks.
> > >
> > > Signed-off-by: Pierre-Louis Bossart <[email protected]>
> > > ---
> > > drivers/soundwire/stream.c | 19 ++++++++++++++++++-
> > > 1 file changed, 18 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
> > > index 53f5e790fcd7..75b9ad1fb1a6 100644
> > > --- a/drivers/soundwire/stream.c
> > > +++ b/drivers/soundwire/stream.c
> > > @@ -1637,7 +1637,24 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
> > > }
> > > }
> > > - return do_bank_switch(stream);
> > > + ret = do_bank_switch(stream);
> > > + if (ret < 0) {
> > > + dev_err(bus->dev, "Bank switch failed: %d\n", ret);
> > > + return ret;
> > > + }
> > > +
> > > + /* make sure alternate bank (previous current) is also disabled */
> > > + list_for_each_entry(m_rt, &stream->master_list, stream_node) {
> > > + bus = m_rt->bus;
> > > + /* Disable port(s) */
> > > + ret = sdw_enable_disable_ports(m_rt, false);
> > > + if (ret < 0) {
> > > + dev_err(bus->dev, "Disable port(s) failed: %d\n", ret);
> > > + return ret;
> > > + }
> > > + }
> > > +
> > > + return 0;
> > > }
> > > /**
> > > --
> > > 2.20.1
> > >
> >

--

2019-08-05 16:57:08

by Sanyog Kale

[permalink] [raw]
Subject: Re: [RFC PATCH 28/40] soundwire: intel: handle disabled links

On Thu, Jul 25, 2019 at 06:40:20PM -0500, Pierre-Louis Bossart wrote:
> On most hardware platforms, SoundWire interfaces are pin-muxed with
> other interfaces (typically DMIC or I2S) and the status of each link
> needs to be checked at boot time.
>
> For Intel platforms, the BIOS provides a menu to enable/disable the
> links separately, and the information is provided to the OS with an
> Intel-specific _DSD property. The same capability will be added to
> revisions of the MIPI DisCo specification.
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/intel.c | 26 ++++++++++++++++++++++----
> include/linux/soundwire/sdw.h | 2 ++
> 2 files changed, 24 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index 796ac2bc8cea..5947fa8e840b 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -90,6 +90,8 @@
> #define SDW_ALH_STRMZCFG_DMAT GENMASK(7, 0)
> #define SDW_ALH_STRMZCFG_CHN GENMASK(19, 16)
>
> +#define SDW_INTEL_QUIRK_MASK_BUS_DISABLE BIT(1)
> +
> enum intel_pdi_type {
> INTEL_PDI_IN = 0,
> INTEL_PDI_OUT = 1,
> @@ -922,7 +924,7 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus)
> struct sdw_master_prop *prop = &bus->prop;
> struct fwnode_handle *link;
> char name[32];
> - int nval, i;
> + u32 quirk_mask;
>
> /* Find master handle */
> snprintf(name, sizeof(name),
> @@ -937,6 +939,14 @@ static int sdw_master_read_intel_prop(struct sdw_bus *bus)
> fwnode_property_read_u32(link,
> "intel-sdw-ip-clock",
> &prop->mclk_freq);
> +
> + fwnode_property_read_u32(link,
> + "intel-quirk-mask",
> + &quirk_mask);
> +
> + if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE)
> + prop->hw_disabled = true;
> +
> return 0;
> }
>
> @@ -997,6 +1007,12 @@ static int intel_probe(struct platform_device *pdev)
> goto err_master_reg;
> }
>
> + if (sdw->cdns.bus.prop.hw_disabled) {
> + dev_info(&pdev->dev, "SoundWire master %d is disabled, ignoring\n",
> + sdw->cdns.bus.link_id);
> + return 0;
> + }
> +
> /* Initialize shim and controller */
> intel_link_power_up(sdw);
> intel_shim_init(sdw);
> @@ -1050,9 +1066,11 @@ static int intel_remove(struct platform_device *pdev)
>
> sdw = platform_get_drvdata(pdev);
>
> - intel_debugfs_exit(sdw);
> - free_irq(sdw->res->irq, sdw);
> - snd_soc_unregister_component(sdw->cdns.dev);
> + if (!sdw->cdns.bus.prop.hw_disabled) {
> + intel_debugfs_exit(sdw);
> + free_irq(sdw->res->irq, sdw);
> + snd_soc_unregister_component(sdw->cdns.dev);
> + }
> sdw_delete_bus_master(&sdw->cdns.bus);
>
> return 0;
> diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
> index c7dfc824be80..f78b076a8782 100644
> --- a/include/linux/soundwire/sdw.h
> +++ b/include/linux/soundwire/sdw.h
> @@ -380,6 +380,7 @@ struct sdw_slave_prop {
> * @err_threshold: Number of times that software may retry sending a single
> * command
> * @mclk_freq: clock reference passed to SoundWire Master, in Hz.
> + * @hw_disabled: if true, the Master is not functional, typically due to pin-mux
> */
> struct sdw_master_prop {
> u32 revision;
> @@ -395,6 +396,7 @@ struct sdw_master_prop {
> bool dynamic_frame;
> u32 err_threshold;
> u32 mclk_freq;
> + bool hw_disabled;

Do we have such cases where some of SoundWire links are disabled and
some enabled?

> };
>
> int sdw_master_read_prop(struct sdw_bus *bus);
> --
> 2.20.1
>

--

2019-08-05 17:02:42

by Sanyog Kale

[permalink] [raw]
Subject: Re: [RFC PATCH 27/40] soundwire: Add Intel resource management algorithm

On Thu, Jul 25, 2019 at 06:40:19PM -0500, Pierre-Louis Bossart wrote:
> This algorithm computes bus parameters like clock frequency, frame
> shape and port transport parameters based on active stream(s) running
> on the bus.
>
> This implementation is optimal for Intel platforms. Developers can
> also implement their own .compute_params() callback for specific
> resource management algorithm.
>
> Credits: this patch is based on an earlier internal contribution by
> Vinod Koul, Sanyog Kale, Shreyas Nc and Hardik Shah. All hard-coded
> values were removed from the initial contribution to use BIOS
> information instead.
>
> FIXME: remove checkpatch report
> WARNING: Reusing the krealloc arg is almost always a bug
> + group->rates = krealloc(group->rates,
>
> Signed-off-by: Pierre-Louis Bossart <[email protected]>
> ---
> drivers/soundwire/Makefile | 2 +-
> drivers/soundwire/algo_dynamic_allocation.c | 403 ++++++++++++++++++++
> drivers/soundwire/bus.c | 3 +
> drivers/soundwire/bus.h | 46 ++-
> drivers/soundwire/stream.c | 20 +
> include/linux/soundwire/sdw.h | 5 +
> 6 files changed, 476 insertions(+), 3 deletions(-)
> create mode 100644 drivers/soundwire/algo_dynamic_allocation.c
>
> diff --git a/drivers/soundwire/Makefile b/drivers/soundwire/Makefile
> index 88990cac48a7..f59a9d4a28fd 100644
> --- a/drivers/soundwire/Makefile
> +++ b/drivers/soundwire/Makefile
> @@ -5,7 +5,7 @@
>
> #Bus Objs
> soundwire-bus-objs := bus_type.o bus.o slave.o mipi_disco.o stream.o \
> - debugfs.o
> + debugfs.o algo_dynamic_allocation.o
>
> obj-$(CONFIG_SOUNDWIRE_BUS) += soundwire-bus.o
>
> diff --git a/drivers/soundwire/algo_dynamic_allocation.c b/drivers/soundwire/algo_dynamic_allocation.c
> new file mode 100644
> index 000000000000..89edb39162b8
> --- /dev/null
> +++ b/drivers/soundwire/algo_dynamic_allocation.c
> @@ -0,0 +1,403 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
> +// Copyright(c) 2015-18 Intel Corporation.
> +
> +/*
> + * Bandwidth management algorithm based on 2^n gears
> + *
> + */
> +
> +#include <linux/device.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/slab.h>
> +#include <linux/soundwire/sdw.h>
> +#include "bus.h"
> +
> +#define SDW_STRM_RATE_GROUPING 1
> +
> +struct sdw_group_params {
> + unsigned int rate;
> + int full_bw;
> + int payload_bw;
> + int hwidth;
> +};
> +
> +struct sdw_group {
> + unsigned int count;
> + unsigned int max_size;
> + unsigned int *rates;
> +};
> +
> +struct sdw_transport_data {
> + int hstart;
> + int hstop;
> + int block_offset;
> + int sub_block_offset;
> +};
> +
> +
> +/**
> + * sdw_compute_port_params: Compute transport and port parameters
> + *
> + * @bus: SDW Bus instance
> + */
> +static int sdw_compute_port_params(struct sdw_bus *bus)
> +{
> + struct sdw_group_params *params = NULL;
> + struct sdw_group group;
> + int ret;
> +
> + ret = sdw_get_group_count(bus, &group);
> + if (ret < 0)
> + goto out;
> +
> + if (group.count == 0)
> + goto out;
> +
> + params = kcalloc(group.count, sizeof(*params), GFP_KERNEL);
> + if (!params) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + /* Compute transport parameters for grouped streams */
> + ret = sdw_compute_group_params(bus, params,
> + &group.rates[0], group.count);
> + if (ret < 0)
> + goto out;
> +
> + _sdw_compute_port_params(bus, params, group.count);
> +
> +out:
> + kfree(params);
> + kfree(group.rates);
> +
> + return ret;
> +}
> +
> +static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq)
> +{
> + struct sdw_master_prop *prop = &bus->prop;
> + int frame_int, frame_freq;
> + int r, c;
> +
> + for (c = 0; c < SDW_FRAME_COLS; c++) {
> + for (r = 0; r < SDW_FRAME_ROWS; r++) {
> + if (sdw_rows[r] != prop->default_row ||
> + sdw_cols[c] != prop->default_col)
> + continue;

Are we only supporting default rows and cols?

> +
> + frame_int = sdw_rows[r] * sdw_cols[c];
> + frame_freq = clk_freq / frame_int;
> +
> + if ((clk_freq - (frame_freq * SDW_FRAME_CTRL_BITS)) <
> + bus->params.bandwidth)
> + continue;
> +
> + bus->params.row = sdw_rows[r];
> + bus->params.col = sdw_cols[c];
> + return 0;
> + }
> + }
> +
> + return -EINVAL;
> +}
> +
> --
> 2.20.1
>

--

2019-08-05 19:12:28

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 27/40] soundwire: Add Intel resource management algorithm


>> +static int sdw_select_row_col(struct sdw_bus *bus, int clk_freq)
>> +{
>> + struct sdw_master_prop *prop = &bus->prop;
>> + int frame_int, frame_freq;
>> + int r, c;
>> +
>> + for (c = 0; c < SDW_FRAME_COLS; c++) {
>> + for (r = 0; r < SDW_FRAME_ROWS; r++) {
>> + if (sdw_rows[r] != prop->default_row ||
>> + sdw_cols[c] != prop->default_col)
>> + continue;
>
> Are we only supporting default rows and cols?

for now yes. Note that the default is defined by firmware and e.g.
different for ICL (50x4) and CML (125x2). The firmware itself also
provides a single clock value so we'd need to override the DSDT or force
the properties to be different to use multiple gears.

This will probably change at some point when we have multiple device per
link. SoundWire 1.2 devices also provide a standard means to control the
clock, otherwise with SoundWire 1.1 the clock management requires quite
a bit of imp-def changes that we have not tested.

>
>> +
>> + frame_int = sdw_rows[r] * sdw_cols[c];
>> + frame_freq = clk_freq / frame_int;
>> +
>> + if ((clk_freq - (frame_freq * SDW_FRAME_CTRL_BITS)) <
>> + bus->params.bandwidth)
>> + continue;
>> +
>> + bus->params.row = sdw_rows[r];
>> + bus->params.col = sdw_cols[c];
>> + return 0;
>> + }
>> + }
>> +
>> + return -EINVAL;
>> +}
>> +
>> --
>> 2.20.1
>>
>

2019-08-05 19:13:40

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 23/40] soundwire: stream: fix disable sequence



On 8/5/19 11:32 AM, Sanyog Kale wrote:
> On Mon, Aug 05, 2019 at 10:33:25AM -0500, Pierre-Louis Bossart wrote:
>>
>>
>> On 8/5/19 4:56 AM, Sanyog Kale wrote:
>>> On Thu, Jul 25, 2019 at 06:40:15PM -0500, Pierre-Louis Bossart wrote:
>>>> When we disable the stream and then call hw_free, two bank switches
>>>> will be handled and as a result we re-enable the stream on hw_free.
>>>>
>>>
>>> I didnt quite get why there will be two bank switches as part of disable flow
>>> which leads to enabling of stream?
>>
>> You have two bank switches, one to stop streaming and on in de-prepare. It's
>> symmetrical with the start sequence, where we do a bank switch to prepare
>> and another to enable.
>
> Got it. I misunderstood it that two bank switches are performed as part of
> disable_stream.
>
>>
>> Let's assume we are using bank0 when streaming.
>>
>> Before the first bank switch, the channel_enable is set to false in the
>> alternate bank1. When the bank switch happens, bank1 become active and the
>> streaming stops. But bank0 registers have not been modified so when we do
>> the second bank switch in de-prepare we make bank0 active, and the ch_enable
>> bits are still set so streaming will restart... When we stop streaming, we
>> need to make sure the ch_enable bits are cleared in the two banks.
>
> This is clear. Even though the channels remains enabled, i believe there
> won't be any data pushed on lines as stream will be closed.

Actually the link remains active. We tested this by setting the PRBS
data mode and the Slave device detects when we artificially inject errors.

There is however no data consumption on the DMA side of the Master IP
since the DMA is indeed stopped.

>
> Regarding mirroring approach, I assume after bank switch we will take
> snapshot of active bank and program same in inactive bank.

That should be the approach yes.

>
>>
>>
>>>
>>>> Make sure the stream is disabled on both banks.
>>>>
>>>> TODO: we need to completely revisit all this and make sure we have a
>>>> mirroring mechanism between current and alternate banks.
>>>>
>>>> Signed-off-by: Pierre-Louis Bossart <[email protected]>
>>>> ---
>>>> drivers/soundwire/stream.c | 19 ++++++++++++++++++-
>>>> 1 file changed, 18 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c
>>>> index 53f5e790fcd7..75b9ad1fb1a6 100644
>>>> --- a/drivers/soundwire/stream.c
>>>> +++ b/drivers/soundwire/stream.c
>>>> @@ -1637,7 +1637,24 @@ static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
>>>> }
>>>> }
>>>> - return do_bank_switch(stream);
>>>> + ret = do_bank_switch(stream);
>>>> + if (ret < 0) {
>>>> + dev_err(bus->dev, "Bank switch failed: %d\n", ret);
>>>> + return ret;
>>>> + }
>>>> +
>>>> + /* make sure alternate bank (previous current) is also disabled */
>>>> + list_for_each_entry(m_rt, &stream->master_list, stream_node) {
>>>> + bus = m_rt->bus;
>>>> + /* Disable port(s) */
>>>> + ret = sdw_enable_disable_ports(m_rt, false);
>>>> + if (ret < 0) {
>>>> + dev_err(bus->dev, "Disable port(s) failed: %d\n", ret);
>>>> + return ret;
>>>> + }
>>>> + }
>>>> +
>>>> + return 0;
>>>> }
>>>> /**
>>>> --
>>>> 2.20.1
>>>>
>>>
>

2019-08-05 19:21:07

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 28/40] soundwire: intel: handle disabled links



On 8/5/19 11:57 AM, Sanyog Kale wrote:
> On Thu, Jul 25, 2019 at 06:40:20PM -0500, Pierre-Louis Bossart wrote:
>> On most hardware platforms, SoundWire interfaces are pin-muxed with
>> other interfaces (typically DMIC or I2S) and the status of each link
>> needs to be checked at boot time.
>>
>> For Intel platforms, the BIOS provides a menu to enable/disable the
>> links separately, and the information is provided to the OS with an
>> Intel-specific _DSD property. The same capability will be added to
>> revisions of the MIPI DisCo specification.

[snip]

>> diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h
>> index c7dfc824be80..f78b076a8782 100644
>> --- a/include/linux/soundwire/sdw.h
>> +++ b/include/linux/soundwire/sdw.h
>> @@ -380,6 +380,7 @@ struct sdw_slave_prop {
>> * @err_threshold: Number of times that software may retry sending a single
>> * command
>> * @mclk_freq: clock reference passed to SoundWire Master, in Hz.
>> + * @hw_disabled: if true, the Master is not functional, typically due to pin-mux
>> */
>> struct sdw_master_prop {
>> u32 revision;
>> @@ -395,6 +396,7 @@ struct sdw_master_prop {
>> bool dynamic_frame;
>> u32 err_threshold;
>> u32 mclk_freq;
>> + bool hw_disabled;
>
> Do we have such cases where some of SoundWire links are disabled and
> some enabled?

Yes, by default my ICL test board uses HDaudio for the codec so the
SoundWire link0 is disabled. If I rework the board and change the BIOS
advanced menu then SoundWire link0 is enabled. This information is
dynamically provided to the OS after the _INI step.
SoundWire-2/3 are used typically for attached DMICs or for a combination
of SoundWire amplifier and mic capture. It's really platform-specific.

>
>> };
>>
>> int sdw_master_read_prop(struct sdw_bus *bus);
>> --
>> 2.20.1
>>
>

2019-08-14 19:57:14

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 31/40] soundwire: intel: move shutdown() callback and don't export symbol



>>>> +void intel_shutdown(struct snd_pcm_substream *substream,
>>>> +            struct snd_soc_dai *dai)
>>>> +{
>>>> +    struct sdw_cdns_dma_data *dma;
>>>> +
>>>> +    dma = snd_soc_dai_get_dma_data(dai, substream);
>>>> +    if (!dma)
>>>> +        return;
>>>> +
>>>> +    snd_soc_dai_set_dma_data(dai, substream, NULL);
>>>> +    kfree(dma);
>>>> +}
>>>
>>> Correct me if I'm wrong, but do we really need to _get_dma_ here?
>>> _set_dma_ seems bulletproof, same for kfree.
>>
>> I must admit I have no idea why we have a reference to DMAs here, this looks
>> like an abuse to store a dai-specific context, and the initial test looks
>> like copy-paste to detect invalid configs, as done in other callbacks. Vinod
>> and Sanyog might have more history than me here.
>
> I dont see snd_soc_dai_set_dma_data() call for
> sdw_cdns_dma_data so somthing is missing (at least in upstream code)
>
> IIRC we should have a snd_soc_dai_set_dma_data() in alloc or some
> initialization routine and we free it here.. Sanyog?

Vinod, I double-checked that we do not indeed have a call to
snd_soc_dai_dma_data(), but there is code in cdns_set_stream() that sets
the relevant dai->playback/capture_dma_data, see below

I am not a big fan of this code, touching the ASoC core internal fields
isn't a good idea in general.

Also not sure why for a DAI we need both _drvdata and _dma_data
(especially for this case where the information stored has absolutely
nothing to do with DMAs).

If the idea was to keep a context that is direction-dependent, that's
likely unnecessary. For the Intel/Cadence case the interfaces can be
configured as playback OR capture, not both concurrently, so the "dma"
information could have been stored in the generic DAI _drvdata.

I have other things to look into for now but this code will likely need
to be cleaned-up at some point to remove unnecessary parts.

int cdns_set_sdw_stream(struct snd_soc_dai *dai,
void *stream, bool pcm, int direction)
{
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
struct sdw_cdns_dma_data *dma;

dma = kzalloc(sizeof(*dma), GFP_KERNEL);
if (!dma)
return -ENOMEM;

if (pcm)
dma->stream_type = SDW_STREAM_PCM;
else
dma->stream_type = SDW_STREAM_PDM;

dma->bus = &cdns->bus;
dma->link_id = cdns->instance;

dma->stream = stream;

>>> this is equivalent to snd_soc_dai_dma_data()

if (direction == SNDRV_PCM_STREAM_PLAYBACK)
dai->playback_dma_data = dma;
else
dai->capture_dma_data = dma;
<<<<
return 0;
}
EXPORT_SYMBOL(cdns_set_sdw_stream);

2019-08-23 10:29:23

by Vinod Koul

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 31/40] soundwire: intel: move shutdown() callback and don't export symbol

On 14-08-19, 14:31, Pierre-Louis Bossart wrote:
>
>
> > > > > +void intel_shutdown(struct snd_pcm_substream *substream,
> > > > > +??????????? struct snd_soc_dai *dai)
> > > > > +{
> > > > > +??? struct sdw_cdns_dma_data *dma;
> > > > > +
> > > > > +??? dma = snd_soc_dai_get_dma_data(dai, substream);
> > > > > +??? if (!dma)
> > > > > +??????? return;
> > > > > +
> > > > > +??? snd_soc_dai_set_dma_data(dai, substream, NULL);
> > > > > +??? kfree(dma);
> > > > > +}
> > > >
> > > > Correct me if I'm wrong, but do we really need to _get_dma_ here?
> > > > _set_dma_ seems bulletproof, same for kfree.
> > >
> > > I must admit I have no idea why we have a reference to DMAs here, this looks
> > > like an abuse to store a dai-specific context, and the initial test looks
> > > like copy-paste to detect invalid configs, as done in other callbacks. Vinod
> > > and Sanyog might have more history than me here.
> >
> > I dont see snd_soc_dai_set_dma_data() call for
> > sdw_cdns_dma_data so somthing is missing (at least in upstream code)
> >
> > IIRC we should have a snd_soc_dai_set_dma_data() in alloc or some
> > initialization routine and we free it here.. Sanyog?
>
> Vinod, I double-checked that we do not indeed have a call to
> snd_soc_dai_dma_data(), but there is code in cdns_set_stream() that sets the
> relevant dai->playback/capture_dma_data, see below
>
> I am not a big fan of this code, touching the ASoC core internal fields
> isn't a good idea in general.

IIRC as long as you stick to single link I do not see this required. The
question comes into picture when we have multi links as you would need
to allocate a soundwire stream and set that for all the sdw DAIs

So, what is the current model of soundwire stream, which entity allocates
that and do you still care about multi-link? is there any machine driver
with soundwire upstream yet?

> Also not sure why for a DAI we need both _drvdata and _dma_data (especially

_drvdata is global for driver whereas _dma_data is typically used per
DAI

> for this case where the information stored has absolutely nothing to do with
> DMAs).
>
> If the idea was to keep a context that is direction-dependent, that's likely
> unnecessary. For the Intel/Cadence case the interfaces can be configured as
> playback OR capture, not both concurrently, so the "dma" information could
> have been stored in the generic DAI _drvdata.
>
> I have other things to look into for now but this code will likely need to
> be cleaned-up at some point to remove unnecessary parts.

Sure please go ahead and do the cleanup.
>
> int cdns_set_sdw_stream(struct snd_soc_dai *dai,
> void *stream, bool pcm, int direction)
> {
> struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
> struct sdw_cdns_dma_data *dma;
>
> dma = kzalloc(sizeof(*dma), GFP_KERNEL);
> if (!dma)
> return -ENOMEM;
>
> if (pcm)
> dma->stream_type = SDW_STREAM_PCM;
> else
> dma->stream_type = SDW_STREAM_PDM;
>
> dma->bus = &cdns->bus;
> dma->link_id = cdns->instance;
>
> dma->stream = stream;
>
> >>> this is equivalent to snd_soc_dai_dma_data()
>
> if (direction == SNDRV_PCM_STREAM_PLAYBACK)
> dai->playback_dma_data = dma;
> else
> dai->capture_dma_data = dma;
> <<<<
> return 0;
> }
> EXPORT_SYMBOL(cdns_set_sdw_stream);

--
~Vinod

2019-08-23 23:33:20

by Pierre-Louis Bossart

[permalink] [raw]
Subject: Re: [alsa-devel] [RFC PATCH 31/40] soundwire: intel: move shutdown() callback and don't export symbol



>>>>>> +void intel_shutdown(struct snd_pcm_substream *substream,
>>>>>> +            struct snd_soc_dai *dai)
>>>>>> +{
>>>>>> +    struct sdw_cdns_dma_data *dma;
>>>>>> +
>>>>>> +    dma = snd_soc_dai_get_dma_data(dai, substream);
>>>>>> +    if (!dma)
>>>>>> +        return;
>>>>>> +
>>>>>> +    snd_soc_dai_set_dma_data(dai, substream, NULL);
>>>>>> +    kfree(dma);
>>>>>> +}
>>>>>
>>>>> Correct me if I'm wrong, but do we really need to _get_dma_ here?
>>>>> _set_dma_ seems bulletproof, same for kfree.
>>>>
>>>> I must admit I have no idea why we have a reference to DMAs here, this looks
>>>> like an abuse to store a dai-specific context, and the initial test looks
>>>> like copy-paste to detect invalid configs, as done in other callbacks. Vinod
>>>> and Sanyog might have more history than me here.
>>>
>>> I dont see snd_soc_dai_set_dma_data() call for
>>> sdw_cdns_dma_data so somthing is missing (at least in upstream code)
>>>
>>> IIRC we should have a snd_soc_dai_set_dma_data() in alloc or some
>>> initialization routine and we free it here.. Sanyog?
>>
>> Vinod, I double-checked that we do not indeed have a call to
>> snd_soc_dai_dma_data(), but there is code in cdns_set_stream() that sets the
>> relevant dai->playback/capture_dma_data, see below
>>
>> I am not a big fan of this code, touching the ASoC core internal fields
>> isn't a good idea in general.
>
> IIRC as long as you stick to single link I do not see this required. The
> question comes into picture when we have multi links as you would need
> to allocate a soundwire stream and set that for all the sdw DAIs
>
> So, what is the current model of soundwire stream, which entity allocates
> that and do you still care about multi-link? is there any machine driver
> with soundwire upstream yet?

yes, multi-link is definitively required and one of the main appeals of
SoundWire. We have a platform with 2 amplifiers on separate links and
they need to be synchronized and handled with the stream concept.

The tentative plan would be to move the stream allocation to the dailink
.init (or equivalent), and make sure each DAI in that link used the same
stream information. There are dependencies on the multi-cpu concept that
Morimoto-san wanted to push, so we'll likely be the first users.

For the DAI trigger, we will need to change the existing API so that a
sdw_stream_enable() can be called multiple times, but only takes effect
when the .trigger of the first DAI in the stream is invoked. This is a
similar behavior than with HDaudio .trigger operations when the SYNC
bits are used.

We will do this when we have a first pass working with all codec drivers
upstream and a basic machine driver upstream with all 4 links working
independently.

Everything is done in public btw, you can track our WIP solutions here:

https://github.com/thesofproject/linux/pull/1140
https://github.com/thesofproject/linux/pull/1141
https://github.com/thesofproject/linux/pull/1142