Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soundwire: intel_ace2x: add fake frame to BRA read command

Intel DMA buffer size need to be a multiple of data block size.
Find the minimal fake data size and extra buffer size to meet the
requirement.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Link: https://patch.msgid.link/20251030070253.1216871-8-yung-chuan.liao@linux.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Bard Liao and committed by
Vinod Koul
8931f5bc 9468bc0e

+56 -5
+56 -5
drivers/soundwire/intel_ace2x.c
··· 44 44 return ret; 45 45 } 46 46 47 + #define READ_PDI1_MIN_SIZE 12 48 + 47 49 static int intel_ace2x_bpt_open_stream(struct sdw_intel *sdw, struct sdw_slave *slave, 48 50 struct sdw_bpt_msg *msg) 49 51 { ··· 55 53 struct sdw_stream_runtime *stream; 56 54 struct sdw_stream_config sconfig; 57 55 struct sdw_port_config *pconfig; 56 + unsigned int pdi0_buf_size_pre_frame; 57 + unsigned int pdi1_buf_size_pre_frame; 58 58 unsigned int pdi0_buffer_size; 59 59 unsigned int tx_dma_bandwidth; 60 60 unsigned int pdi1_buffer_size; 61 61 unsigned int rx_dma_bandwidth; 62 + unsigned int fake_num_frames; 62 63 unsigned int data_per_frame; 63 64 unsigned int tx_total_bytes; 64 65 struct sdw_cdns_pdi *pdi0; 65 66 struct sdw_cdns_pdi *pdi1; 67 + unsigned int rx_alignment; 68 + unsigned int tx_alignment; 66 69 unsigned int num_frames; 70 + unsigned int fake_size; 71 + unsigned int tx_pad; 72 + unsigned int rx_pad; 67 73 int command; 68 74 int ret1; 69 75 int ret; ··· 148 138 149 139 command = (msg->flags & SDW_MSG_FLAG_WRITE) ? 0 : 1; 150 140 141 + ret = sdw_cdns_bpt_find_bandwidth(command, cdns->bus.params.row, 142 + cdns->bus.params.col, 143 + prop->default_frame_rate, 144 + &tx_dma_bandwidth, &rx_dma_bandwidth); 145 + if (ret < 0) 146 + goto deprepare_stream; 147 + 151 148 ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, cdns->bus.params.col, 152 149 msg->len, SDW_BPT_MSG_MAX_BYTES, &data_per_frame, 153 150 &pdi0_buffer_size, &pdi1_buffer_size, &num_frames); ··· 165 148 sdw->bpt_ctx.pdi1_buffer_size = pdi1_buffer_size; 166 149 sdw->bpt_ctx.num_frames = num_frames; 167 150 sdw->bpt_ctx.data_per_frame = data_per_frame; 168 - tx_dma_bandwidth = div_u64((u64)pdi0_buffer_size * 8 * (u64)prop->default_frame_rate, 169 - num_frames); 170 - rx_dma_bandwidth = div_u64((u64)pdi1_buffer_size * 8 * (u64)prop->default_frame_rate, 171 - num_frames); 151 + 152 + rx_alignment = hda_sdw_bpt_get_buf_size_alignment(rx_dma_bandwidth); 153 + tx_alignment = hda_sdw_bpt_get_buf_size_alignment(tx_dma_bandwidth); 154 + 155 + if (command) { /* read */ 156 + /* Get buffer size of a full frame */ 157 + ret = sdw_cdns_bpt_find_buffer_sizes(command, cdns->bus.params.row, 158 + cdns->bus.params.col, 159 + data_per_frame, SDW_BPT_MSG_MAX_BYTES, 160 + &data_per_frame, &pdi0_buf_size_pre_frame, 161 + &pdi1_buf_size_pre_frame, &fake_num_frames); 162 + if (ret < 0) 163 + goto deprepare_stream; 164 + 165 + /* find fake pdi1 buffer size */ 166 + rx_pad = rx_alignment - (pdi1_buffer_size % rx_alignment); 167 + while (rx_pad <= READ_PDI1_MIN_SIZE) 168 + rx_pad += rx_alignment; 169 + 170 + pdi1_buffer_size += rx_pad; 171 + /* It is fine if we request more than enough byte to read */ 172 + fake_num_frames = DIV_ROUND_UP(rx_pad, pdi1_buf_size_pre_frame); 173 + fake_size = fake_num_frames * data_per_frame; 174 + 175 + /* find fake pdi0 buffer size */ 176 + pdi0_buffer_size += (fake_num_frames * pdi0_buf_size_pre_frame); 177 + tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment); 178 + pdi0_buffer_size += tx_pad; 179 + } else { /* write */ 180 + /* 181 + * For the write command, the rx data block is 4, and the rx buffer size of a frame 182 + * is 8. So the rx buffer size (pdi0_buffer_size) is always a multiple of rx 183 + * alignment. 184 + */ 185 + tx_pad = tx_alignment - (pdi0_buffer_size % tx_alignment); 186 + pdi0_buffer_size += tx_pad; 187 + } 172 188 173 189 dev_dbg(cdns->dev, "Message len %d transferred in %d frames (%d per frame)\n", 174 190 msg->len, num_frames, data_per_frame); ··· 227 177 ret = sdw_cdns_prepare_read_dma_buffer(msg->dev_num, msg->addr, msg->len, 228 178 data_per_frame, 229 179 sdw->bpt_ctx.dmab_tx_bdl.area, 230 - pdi0_buffer_size, &tx_total_bytes, 0); 180 + pdi0_buffer_size, &tx_total_bytes, 181 + fake_size); 231 182 } 232 183 233 184 if (!ret)