Message ID | 20201202204645.23891-5-yung-chuan.liao@linux.intel.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | soundwire/regmap: use _no_pm routines | expand |
On 03-12-20, 04:46, Bard Liao wrote: > sdw_update_slave_status will be invoked when a codec is attached, > and the codec driver will initialize the codec with regmap functions > while the codec device is pm_runtime suspended. > > regmap routines currently rely on regular SoundWire IO functions, > which will call pm_runtime_get_sync()/put_autosuspend. > > This causes a deadlock where the resume routine waits for an > initialization complete signal that while the initialization complete > can only be reached when the resume completes. > > The only solution if we allow regmap functions to be used in resume > operations as well as during codec initialization is to use _no_pm > routines. The duty of making sure the bus is operational needs to be > handled above the regmap level. > > Fixes: 7c22ce6e21840 ('regmap: Add SoundWire bus support') > Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> > Reviewed-by: Rander Wang <rander.wang@linux.intel.com> > --- > drivers/base/regmap/regmap-sdw.c | 4 ++-- > drivers/soundwire/bus.c | 6 ++++-- > include/linux/soundwire/sdw.h | 2 ++ > 3 files changed, 8 insertions(+), 4 deletions(-) > > diff --git a/drivers/base/regmap/regmap-sdw.c b/drivers/base/regmap/regmap-sdw.c > index c92d614b4943..4b8d2d010cab 100644 > --- a/drivers/base/regmap/regmap-sdw.c > +++ b/drivers/base/regmap/regmap-sdw.c > @@ -11,7 +11,7 @@ static int regmap_sdw_write(void *context, unsigned int reg, unsigned int val) > struct device *dev = context; > struct sdw_slave *slave = dev_to_sdw_dev(dev); > > - return sdw_write(slave, reg, val); > + return sdw_write_no_pm(slave, reg, val); > } > > static int regmap_sdw_read(void *context, unsigned int reg, unsigned int *val) > @@ -20,7 +20,7 @@ static int regmap_sdw_read(void *context, unsigned int reg, unsigned int *val) > struct sdw_slave *slave = dev_to_sdw_dev(dev); > int read; > > - read = sdw_read(slave, reg); > + read = sdw_read_no_pm(slave, reg); > if (read < 0) > return read; > > diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c > index 86c339d77a39..c5ea59673dee 100644 > --- a/drivers/soundwire/bus.c > +++ b/drivers/soundwire/bus.c > @@ -405,10 +405,11 @@ sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) > return sdw_transfer(slave->bus, &msg); > } > > -static int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value) > +int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value) > { > return sdw_nwrite_no_pm(slave, addr, 1, &value); > } > +EXPORT_SYMBOL(sdw_write_no_pm); Why not export this is patch 1..? > > static int > sdw_bread_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr) > @@ -476,7 +477,7 @@ int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 val > } > EXPORT_SYMBOL(sdw_bwrite_no_pm_unlocked); > > -static int > +int > sdw_read_no_pm(struct sdw_slave *slave, u32 addr) > { > u8 buf; > @@ -488,6 +489,7 @@ sdw_read_no_pm(struct sdw_slave *slave, u32 addr) > else > return buf; > } > +EXPORT_SYMBOL(sdw_read_no_pm); > > static int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val) > { > diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h > index f0b01b728640..d08039d65825 100644 > --- a/include/linux/soundwire/sdw.h > +++ b/include/linux/soundwire/sdw.h > @@ -1005,6 +1005,8 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus); > > int sdw_read(struct sdw_slave *slave, u32 addr); > int sdw_write(struct sdw_slave *slave, u32 addr, u8 value); > +int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value); > +int sdw_read_no_pm(struct sdw_slave *slave, u32 addr); > int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val); > int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val); > > -- > 2.17.1
>> -static int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value) >> +int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value) >> { >> return sdw_nwrite_no_pm(slave, addr, 1, &value); >> } >> +EXPORT_SYMBOL(sdw_write_no_pm); > > Why not export this is patch 1..? yes, good point. I guess Bard and I were debugging in parallel and missed this. thanks for pointing it out.
diff --git a/drivers/base/regmap/regmap-sdw.c b/drivers/base/regmap/regmap-sdw.c index c92d614b4943..4b8d2d010cab 100644 --- a/drivers/base/regmap/regmap-sdw.c +++ b/drivers/base/regmap/regmap-sdw.c @@ -11,7 +11,7 @@ static int regmap_sdw_write(void *context, unsigned int reg, unsigned int val) struct device *dev = context; struct sdw_slave *slave = dev_to_sdw_dev(dev); - return sdw_write(slave, reg, val); + return sdw_write_no_pm(slave, reg, val); } static int regmap_sdw_read(void *context, unsigned int reg, unsigned int *val) @@ -20,7 +20,7 @@ static int regmap_sdw_read(void *context, unsigned int reg, unsigned int *val) struct sdw_slave *slave = dev_to_sdw_dev(dev); int read; - read = sdw_read(slave, reg); + read = sdw_read_no_pm(slave, reg); if (read < 0) return read; diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 86c339d77a39..c5ea59673dee 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -405,10 +405,11 @@ sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) return sdw_transfer(slave->bus, &msg); } -static int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value) +int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value) { return sdw_nwrite_no_pm(slave, addr, 1, &value); } +EXPORT_SYMBOL(sdw_write_no_pm); static int sdw_bread_no_pm(struct sdw_bus *bus, u16 dev_num, u32 addr) @@ -476,7 +477,7 @@ int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 val } EXPORT_SYMBOL(sdw_bwrite_no_pm_unlocked); -static int +int sdw_read_no_pm(struct sdw_slave *slave, u32 addr) { u8 buf; @@ -488,6 +489,7 @@ sdw_read_no_pm(struct sdw_slave *slave, u32 addr) else return buf; } +EXPORT_SYMBOL(sdw_read_no_pm); static int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val) { diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index f0b01b728640..d08039d65825 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -1005,6 +1005,8 @@ int sdw_bus_exit_clk_stop(struct sdw_bus *bus); int sdw_read(struct sdw_slave *slave, u32 addr); int sdw_write(struct sdw_slave *slave, u32 addr, u8 value); +int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value); +int sdw_read_no_pm(struct sdw_slave *slave, u32 addr); int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val); int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);