diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 6013f963f4821b..1efbc04ff5b5c0 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -13,6 +13,9 @@ #include "irq.h" #include "sysfs_local.h" +#define DEFAULT_BRA_WRITE_THRESHOLD 800 +#define DEFAULT_BRA_READ_THRESHOLD 400 + static DEFINE_IDA(sdw_bus_ida); static int sdw_get_id(struct sdw_bus *bus) @@ -87,6 +90,8 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, lockdep_register_key(&bus->bus_lock_key); __mutex_init(&bus->bus_lock, "bus_lock", &bus->bus_lock_key); + mutex_init(&bus->bpt_lock); + INIT_LIST_HEAD(&bus->slaves); INIT_LIST_HEAD(&bus->m_rt_list); @@ -163,6 +168,11 @@ int sdw_bus_master_add(struct sdw_bus *bus, struct device *parent, bus->params.curr_bank = SDW_BANK0; bus->params.next_bank = SDW_BANK1; + if (!bus->bpt_w_threshold) + bus->bpt_w_threshold = DEFAULT_BRA_WRITE_THRESHOLD; + if (!bus->bpt_r_threshold) + bus->bpt_r_threshold = DEFAULT_BRA_READ_THRESHOLD; + return 0; } EXPORT_SYMBOL(sdw_bus_master_add); @@ -439,6 +449,46 @@ static int sdw_ntransfer_no_pm(struct sdw_slave *slave, u32 addr, u8 flags, return 0; } +static int sdw_ntransfer_no_pm_bpt(struct sdw_slave *slave, u32 addr, u8 flags, + size_t count, u8 *val) +{ + struct sdw_bpt_section sec; + struct sdw_bpt_msg msg; + size_t size; + int retry = 5; + int ret; + + msg.sections = 1; + msg.dev_num = slave->dev_num; + msg.flags = flags; + msg.sec = &sec; + + while (count) { + size = min_t(size_t, count, SDW_BPT_MSG_MAX_BYTES); + + sec.addr = addr; + sec.len = size; + sec.buf = val; + + do { + ret = sdw_bpt_send_sync(slave->bus, slave, &msg); + if (ret == -EAGAIN) + msleep(10); + retry--; + } while (ret == -EAGAIN && retry > 0); + + if (ret < 0) + return ret; + + addr += size; + val += size; + count -= size; + retry = 5; + } + + return 0; +} + /** * sdw_nread_no_pm() - Read "n" contiguous SDW Slave registers with no PM * @slave: SDW Slave @@ -447,10 +497,26 @@ static int sdw_ntransfer_no_pm(struct sdw_slave *slave, u32 addr, u8 flags, * @val: Buffer for values to be read * * Note that if the message crosses a page boundary each page will be - * transferred under a separate invocation of the msg_lock. + * transferred under a separate invocation of the msg_lock if it is not + * transferred via BPT. */ int sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) { + struct sdw_bus *bus = slave->bus; + int ret; + + if (!bus->ops->bpt_send_async || !bus->ops->bpt_wait || + count < bus->bpt_r_threshold) + goto fallback; + + ret = sdw_ntransfer_no_pm_bpt(slave, addr, SDW_MSG_FLAG_READ, count, val); + if (!ret) + return 0; + + dev_dbg(&slave->dev, + "BPT read failed for addr %x, count %zu, ret %d fallback to normal read\n", + addr, count, ret); +fallback: return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_READ, count, val); } EXPORT_SYMBOL(sdw_nread_no_pm); @@ -463,10 +529,26 @@ EXPORT_SYMBOL(sdw_nread_no_pm); * @val: Buffer for values to be written * * Note that if the message crosses a page boundary each page will be - * transferred under a separate invocation of the msg_lock. + * transferred under a separate invocation of the msg_lock if it is not + * transferred via BPT. */ int sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val) { + struct sdw_bus *bus = slave->bus; + int ret; + + if (!bus->ops->bpt_send_async || !bus->ops->bpt_wait || + count < bus->bpt_w_threshold) + goto fallback; + + ret = sdw_ntransfer_no_pm_bpt(slave, addr, SDW_MSG_FLAG_WRITE, count, (u8 *)val); + if (!ret) + return 0; + + dev_dbg(&slave->dev, + "BPT write failed for addr %x, count %zu, ret %d fallback to normal write\n", + addr, count, ret); +fallback: return sdw_ntransfer_no_pm(slave, addr, SDW_MSG_FLAG_WRITE, count, (u8 *)val); } EXPORT_SYMBOL(sdw_nwrite_no_pm); @@ -604,7 +686,8 @@ EXPORT_SYMBOL(sdw_update); * This version of the function will take a PM reference to the slave * device. * Note that if the message crosses a page boundary each page will be - * transferred under a separate invocation of the msg_lock. + * transferred under a separate invocation of the msg_lock if it is not + * transferred via BPT. */ int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) { @@ -635,7 +718,8 @@ EXPORT_SYMBOL(sdw_nread); * This version of the function will take a PM reference to the slave * device. * Note that if the message crosses a page boundary each page will be - * transferred under a separate invocation of the msg_lock. + * transferred under a separate invocation of the msg_lock if it is not + * transferred via BPT. */ int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val) { @@ -2094,6 +2178,7 @@ EXPORT_SYMBOL(sdw_clear_slave_status); int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg) { int len = 0; + int ret; int i; for (i = 0; i < msg->sections; i++) @@ -2118,13 +2203,26 @@ int sdw_bpt_send_async(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_ return -EOPNOTSUPP; } - return bus->ops->bpt_send_async(bus, slave, msg); + /* Serialize BPT/BRA transfers per bus: PDIs and DMA resources are shared */ + mutex_lock(&bus->bpt_lock); + + ret = bus->ops->bpt_send_async(bus, slave, msg); + if (ret < 0) + mutex_unlock(&bus->bpt_lock); + + /* on success the lock is held until sdw_bpt_wait() */ + return ret; } EXPORT_SYMBOL(sdw_bpt_send_async); int sdw_bpt_wait(struct sdw_bus *bus, struct sdw_slave *slave, struct sdw_bpt_msg *msg) { - return bus->ops->bpt_wait(bus, slave, msg); + int ret; + + ret = bus->ops->bpt_wait(bus, slave, msg); + mutex_unlock(&bus->bpt_lock); + + return ret; } EXPORT_SYMBOL(sdw_bpt_wait); diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 3e0d21132ef2f7..cfcc7228bc199a 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -1028,6 +1028,10 @@ struct sdw_stream_runtime { * are supported. This flag is populated by drivers after reading * appropriate firmware (ACPI/DT). * @lane_used_bandwidth: how much bandwidth in bits per second is used by each lane + * @bpt_w_threshold: Message-size threshold (bytes) above which BPT write is used. + * If set to 0, a default is used. + * @bpt_r_threshold: Message-size threshold (bytes) above which BPT read is used. + * If set to 0, a default is used. */ struct sdw_bus { struct device *dev; @@ -1044,6 +1048,7 @@ struct sdw_bus { int stream_refcount; int bpt_stream_refcount; struct sdw_stream_runtime *bpt_stream; + struct mutex bpt_lock; /* serialize BPT/BRA transfers per bus */ const struct sdw_master_ops *ops; const struct sdw_master_port_ops *port_ops; struct sdw_master_prop prop; @@ -1063,6 +1068,8 @@ struct sdw_bus { #endif bool multi_link; unsigned int lane_used_bandwidth[SDW_MAX_LANES]; + unsigned int bpt_w_threshold; + unsigned int bpt_r_threshold; }; struct sdw_stream_runtime *sdw_alloc_stream(const char *stream_name, enum sdw_stream_type type); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 77c7d2bc6fa211..78710e872244fb 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -790,7 +790,6 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) { struct pci_dev *pci = to_pci_dev(sdev->dev); struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; - const struct sof_intel_dsp_desc *chip; int ret = 0; hdev->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec", @@ -904,26 +903,12 @@ int hda_dsp_probe(struct snd_sof_dev *sdev) INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work); } - chip = get_chip_info(sdev->pdata); - if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0) { - ret = hda_sdw_startup(sdev); - if (ret < 0) { - dev_err(sdev->dev, "could not startup SoundWire links\n"); - goto disable_pp_cap; - } - } - init_waitqueue_head(&hdev->waitq); hdev->nhlt = intel_nhlt_init(sdev->dev); return 0; -disable_pp_cap: - if (!sdev->dspless_mode_selected) { - hda_dsp_ctrl_ppcap_int_enable(sdev, false); - hda_dsp_ctrl_ppcap_enable(sdev, false); - } free_ipc_irq: free_irq(sdev->ipc_irq, sdev); free_irq_vector: diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 83703ebc6385bc..dffcbc8811e582 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -73,23 +73,6 @@ static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev) return 0; } -static int lnl_dsp_post_fw_run(struct snd_sof_dev *sdev) -{ - if (sdev->first_boot) { - struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; - - /* Check if IMR boot is usable */ - if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT)) { - hda->imrboot_supported = true; - debugfs_create_bool("skip_imr_boot", - 0644, sdev->debugfs_root, - &hda->skip_imr_boot); - } - } - - return 0; -} - int sof_lnl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops) { int ret; @@ -104,9 +87,6 @@ int sof_lnl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops) dsp_ops->remove = lnl_hda_dsp_remove; } - /* post fw run */ - dsp_ops->post_fw_run = lnl_dsp_post_fw_run; - /* PM */ if (!sdev->dspless_mode_selected) { dsp_ops->resume = lnl_hda_dsp_resume;