[PATCH v1 5/5] i2c: i2c-qcom-geni: Add Block event interrupt support
Jyothi Kumar Seerapu
quic_jseerapu at quicinc.com
Mon Oct 28 06:04:07 UTC 2024
On 10/16/2024 8:36 PM, Andi Shyti wrote:
> Hi Jyothi,
>
> ...
>
>> @@ -523,26 +576,49 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
>> enum dma_transfer_direction dma_dirn;
>> struct dma_async_tx_descriptor *desc;
>> int ret;
>> + struct gpi_multi_xfer *gi2c_gpi_xfer;
>> + dma_cookie_t cookie;
>>
>> peripheral = config->peripheral_config;
>> -
>> - dma_buf = i2c_get_dma_safe_msg_buf(msg, 1);
>> - if (!dma_buf)
>> + gi2c_gpi_xfer = &peripheral->multi_xfer;
>> + gi2c_gpi_xfer->msg_idx_cnt = cur_msg_idx;
>> + dma_buf = gi2c_gpi_xfer->dma_buf[gi2c_gpi_xfer->buf_idx];
>> + addr = gi2c_gpi_xfer->dma_addr[gi2c_gpi_xfer->buf_idx];
>> +
>> + dma_buf = i2c_get_dma_safe_msg_buf(&msgs[gi2c_gpi_xfer->msg_idx_cnt], 1);
>> + if (!dma_buf) {
>> + gi2c->err = -ENOMEM;
>> return -ENOMEM;
>> + }
>>
>> if (op == I2C_WRITE)
>> map_dirn = DMA_TO_DEVICE;
>> else
>> map_dirn = DMA_FROM_DEVICE;
>>
>> - addr = dma_map_single(gi2c->se.dev->parent, dma_buf, msg->len, map_dirn);
>> + addr = dma_map_single(gi2c->se.dev->parent,
>> + dma_buf, msgs[gi2c_gpi_xfer->msg_idx_cnt].len,
>
> You could save msgs[gi2c_gpi_xfer->msg_idx_cnt] in a separate
> variable to avoid this extra indexing.
>
Thanks Andi, moved gi2c_gpi_xfer->msg_idx_cnt to separate local variable.
>> + map_dirn);
>> if (dma_mapping_error(gi2c->se.dev->parent, addr)) {
>> - i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
>> + i2c_put_dma_safe_msg_buf(dma_buf, &msgs[gi2c_gpi_xfer->msg_idx_cnt],
>> + false);
>> + gi2c->err = -ENOMEM;
>> return -ENOMEM;
>> }
>>
>> + if (gi2c->is_tx_multi_xfer) {
>> + if (((gi2c_gpi_xfer->msg_idx_cnt + 1) % NUM_MSGS_PER_IRQ))
>> + peripheral->flags |= QCOM_GPI_BLOCK_EVENT_IRQ;
>> + else
>> + peripheral->flags &= ~QCOM_GPI_BLOCK_EVENT_IRQ;
>> +
>> + /* BEI bit to be cleared for last TRE */
>> + if (gi2c_gpi_xfer->msg_idx_cnt == gi2c->num_msgs - 1)
>> + peripheral->flags &= ~QCOM_GPI_BLOCK_EVENT_IRQ;
>> + }
>> +
>> /* set the length as message for rx txn */
>> - peripheral->rx_len = msg->len;
>> + peripheral->rx_len = msgs[gi2c_gpi_xfer->msg_idx_cnt].len;
>> peripheral->op = op;
>>
>> ret = dmaengine_slave_config(dma_chan, config);
>> @@ -560,25 +636,56 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
>> else
>> dma_dirn = DMA_DEV_TO_MEM;
>>
>> - desc = dmaengine_prep_slave_single(dma_chan, addr, msg->len, dma_dirn, flags);
>> + desc = dmaengine_prep_slave_single(dma_chan, addr,
>> + msgs[gi2c_gpi_xfer->msg_idx_cnt].len,
>> + dma_dirn, flags);
>> if (!desc) {
>> dev_err(gi2c->se.dev, "prep_slave_sg failed\n");
>> - ret = -EIO;
>> + gi2c->err = -EIO;
>> goto err_config;
>> }
>>
>> desc->callback_result = i2c_gpi_cb_result;
>> desc->callback_param = gi2c;
>>
>> - dmaengine_submit(desc);
>> - *buf = dma_buf;
>> - *dma_addr_p = addr;
>> + if (!((msgs[cur_msg_idx].flags & I2C_M_RD) && op == I2C_WRITE)) {
>> + gi2c_gpi_xfer->msg_idx_cnt++;
>> + gi2c_gpi_xfer->buf_idx = (cur_msg_idx + 1) % QCOM_GPI_MAX_NUM_MSGS;
>> + }
>> + cookie = dmaengine_submit(desc);
>> + if (dma_submit_error(cookie)) {
>> + dev_err(gi2c->se.dev,
>> + "%s: dmaengine_submit failed (%d)\n", __func__, cookie);
>> + return -EINVAL;
>
> goto err_config?
yes, updated it.
>
>> + }
>>
>> + if (gi2c->is_tx_multi_xfer) {
>> + dma_async_issue_pending(gi2c->tx_c);
>> + if ((cur_msg_idx == (gi2c->num_msgs - 1)) ||
>> + (gi2c_gpi_xfer->msg_idx_cnt >=
>> + QCOM_GPI_MAX_NUM_MSGS + gi2c_gpi_xfer->freed_msg_cnt)) {
>> + ret = gpi_multi_desc_process(gi2c->se.dev, gi2c_gpi_xfer,
>> + gi2c->num_msgs, XFER_TIMEOUT,
>> + &gi2c->done);
>> + if (ret) {
>> + dev_dbg(gi2c->se.dev,
>> + "I2C multi write msg transfer timeout: %d\n",
>> + ret);
>
> if you are returning an error, then print an error.
sure, updated it to error in V2 patch.
>
>> + gi2c->err = -ETIMEDOUT;
>
> gi2c->err = ret?
Yes in this case, ret is -ETIMEDOUT, so updated in V2 patch as
gi2c->err= ret.
>
>> + goto err_config;
>> + }
>> + }
>> + } else {
>> + /* Non multi descriptor message transfer */
>> + *buf = dma_buf;
>> + *dma_addr_p = addr;
>> + }
>> return 0;
>>
>> err_config:
>> - dma_unmap_single(gi2c->se.dev->parent, addr, msg->len, map_dirn);
>> - i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
>> + dma_unmap_single(gi2c->se.dev->parent, addr,
>> + msgs[cur_msg_idx].len, map_dirn);
>> + i2c_put_dma_safe_msg_buf(dma_buf, &msgs[cur_msg_idx], false);
>> return ret;
>
> I would have one more label here:
>
> out:
> gi2c->err = ret;
>
> return ret;
>
> in order to avoid always assigning twice
Thanks, added new label as out and handled it.
>
>> }
>>
>> @@ -590,6 +697,7 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
>> unsigned long time_left;
>> dma_addr_t tx_addr, rx_addr;
>> void *tx_buf = NULL, *rx_buf = NULL;
>> + struct gpi_multi_xfer *tx_multi_xfer;
>> const struct geni_i2c_clk_fld *itr = gi2c->clk_fld;
>>
>> config.peripheral_config = &peripheral;
>> @@ -603,6 +711,39 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
>> peripheral.set_config = 1;
>> peripheral.multi_msg = false;
>>
>> + gi2c->gpi_config = &peripheral;
>> + gi2c->num_msgs = num;
>> + gi2c->is_tx_multi_xfer = false;
>> + gi2c->tx_irq_cnt = 0;
>> +
>> + tx_multi_xfer = &peripheral.multi_xfer;
>> + tx_multi_xfer->msg_idx_cnt = 0;
>> + tx_multi_xfer->buf_idx = 0;
>> + tx_multi_xfer->unmap_msg_cnt = 0;
>> + tx_multi_xfer->freed_msg_cnt = 0;
>> + tx_multi_xfer->irq_msg_cnt = 0;
>> + tx_multi_xfer->irq_cnt = 0;
>
> you can initialize tx_multi_xfer to "{ };" to avoid all these
> " = 0"
Sure, done memset tx_multi_xfer to 0 in V2 patch.
>
>> +
>> + /*
>> + * If number of write messages are four and higher then
>> + * configure hardware for multi descriptor transfers with BEI.
>> + */
>> + if (num >= MIN_NUM_OF_MSGS_MULTI_DESC) {
>> + gi2c->is_tx_multi_xfer = true;
>> + for (i = 0; i < num; i++) {
>> + if (msgs[i].flags & I2C_M_RD) {
>> + /*
>> + * Multi descriptor transfer with BEI
>> + * support is enabled for write transfers.
>> + * Add BEI optimization support for read
>> + * transfers later.
>> + */
>> + gi2c->is_tx_multi_xfer = false;
>> + break;
>> + }
>> + }
>> + }
>> +
>> for (i = 0; i < num; i++) {
>> gi2c->cur = &msgs[i];
>> gi2c->err = 0;
>> @@ -613,14 +754,16 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
>> peripheral.stretch = 1;
>>
>> peripheral.addr = msgs[i].addr;
>> + if (i > 0 && (!(msgs[i].flags & I2C_M_RD)))
>> + peripheral.multi_msg = false;
>>
>> - ret = geni_i2c_gpi(gi2c, &msgs[i], &config,
>> + ret = geni_i2c_gpi(gi2c, msgs, i, &config,
>
> what is the point of passing 'i' if you always refer to msgs[i]
> in geni_i2c_gpi()?
Handled with new variable in "geni_i2c_gpi "and so no need to pass
current i2c msg index, removed it in V2 patch.
>
>> &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c);
>> if (ret)
>> goto err;
>>
>> if (msgs[i].flags & I2C_M_RD) {
>> - ret = geni_i2c_gpi(gi2c, &msgs[i], &config,
>> + ret = geni_i2c_gpi(gi2c, msgs, i, &config,
>> &rx_addr, &rx_buf, I2C_READ, gi2c->rx_c);
>> if (ret)
>> goto err;
>> @@ -628,18 +771,28 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
>> dma_async_issue_pending(gi2c->rx_c);
>> }
>>
>> - dma_async_issue_pending(gi2c->tx_c);
>> -
>> - time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
>> - if (!time_left)
>> - gi2c->err = -ETIMEDOUT;
>> + if (!gi2c->is_tx_multi_xfer) {
>> + dma_async_issue_pending(gi2c->tx_c);
>> + time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT);
>> + if (!time_left) {
>> + dev_err(gi2c->se.dev, "%s:I2C timeout\n", __func__);
>> + gi2c->err = -ETIMEDOUT;
>> + }
>> + }
>>
>> if (gi2c->err) {
>> ret = gi2c->err;
>> goto err;
>> }
>>
>> - geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr);
>> + if (!gi2c->is_tx_multi_xfer) {
>> + geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr);
>> + } else {
>> + if (gi2c->tx_irq_cnt != tx_multi_xfer->irq_cnt) {
>
> else if (...) {
> ...
> }
Sure, else if used here in V2 patch.
>
> Andi
Regards,
JyothiKumar
More information about the dri-devel
mailing list