Received: by 10.223.185.116 with SMTP id b49csp3744449wrg; Mon, 19 Feb 2018 05:22:40 -0800 (PST) X-Google-Smtp-Source: AH8x2274gHPqScq2EtIpDri1mYNldrT7YygMHfSNhBC0kJwPZvOKNtgVnQLlOVRkERoO3+dCEwZ6 X-Received: by 2002:a17:902:b2c6:: with SMTP id x6-v6mr14178305plw.285.1519046560242; Mon, 19 Feb 2018 05:22:40 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519046560; cv=none; d=google.com; s=arc-20160816; b=opc3cgWe2UE/+mm+OplOYJuKvlbiw0zz5Ff2wEV/39SnybB2nwbiPXXsuCoUvL9hCy XAmT6NgjIkCZswG7kLEXTDMK4YvZMCu1mXSX7qXgSrUjXRksutBbfyzNDzzuDG/wAk9f XTlnBFis5dewv8zxvtXthvQekxrG46tbX9MR2EDSYmBvmTBis5q9TgBli2kI/FiE53Bn 8qsn8quSh2lQqXrCVAk4/8au607AgbqJZ9ZQSoTD2MTK7VMrMekZhbVYamao7eV9Zl4q g24JVtbNOE+JaOBELQsWO28cDuAzwzVVqR7hHtvfB0oIFWGe8gfSLsM77EGOJ2BrcVLd csnA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:message-id:references :in-reply-to:subject:cc:to:from:date:content-transfer-encoding :mime-version:dkim-signature:dkim-signature :arc-authentication-results; bh=9RMw4d4QjPcWXayIdKy7EUlUVSAGn+TH7QzqQCNeVJU=; b=CqmeDxK+mBV9PXfIboJ1jaO1xQxBwnuvN5rQni1QCLuzyh4A28tk8e6qE1qIpMA1a7 ndL9lbW28IW1YH2SVydvgKQP+KJ/LirqlbvjTm5IEA4SrpjY/Mm5z7dLXIT5NG2+7JRQ 0cx9evQtpfDrvBrqdaSiTbtUQKjdN6bVvB+2zFNp/QMS+bCh6CTAZHiwFl0nx2NS1m/h HiG5RE4k2ctQwjSvMLSGxyjCTw7BTZeog9I3Opy6FwqRNKXMEVqLyGJmwkPfM27KPDCv pIdpbrDcr9qKwYFboYk+1ZzT5mnImkIdpFiG3fcsAAh4TzqNZxDwlSSKu63q6kqAhvc8 4oeg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@codeaurora.org header.s=default header.b=SOBjqTXL; dkim=pass header.i=@codeaurora.org header.s=default header.b=Vm5EIc2C; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l4si3859526pgc.586.2018.02.19.05.22.25; Mon, 19 Feb 2018 05:22:40 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@codeaurora.org header.s=default header.b=SOBjqTXL; dkim=pass header.i=@codeaurora.org header.s=default header.b=Vm5EIc2C; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752811AbeBSNVj (ORCPT + 99 others); Mon, 19 Feb 2018 08:21:39 -0500 Received: from smtp.codeaurora.org ([198.145.29.96]:50650 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752666AbeBSNVh (ORCPT ); Mon, 19 Feb 2018 08:21:37 -0500 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id E1E3860558; Mon, 19 Feb 2018 13:21:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1519046496; bh=RLlT+/8p1Kj6d7DfDyjV/mPOq6YNQ0J4uM+Z/xiFkTY=; h=Date:From:To:Cc:Subject:In-Reply-To:References:From; b=SOBjqTXLmAwlX9a14qg/PHjcw2f4KOkaQ0gXiLpkeWyH4uSto28sZsIZOWseAPRb/ PU4bOZIMyobG2TgAFp98uL3iiaa6t/5xoPH1IwcszUnPL78boRwr92B8uxeKGz2vIR l+tvS6vt8/SaMAWN2jS1SkxtsL32dpFnNSsvDln4= X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on pdx-caf-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.8 required=2.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED,T_DKIM_INVALID autolearn=no autolearn_force=no version=3.4.0 Received: from mail.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.codeaurora.org (Postfix) with ESMTP id A69B860558; Mon, 19 Feb 2018 13:21:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1519046495; bh=RLlT+/8p1Kj6d7DfDyjV/mPOq6YNQ0J4uM+Z/xiFkTY=; h=Date:From:To:Cc:Subject:In-Reply-To:References:From; b=Vm5EIc2CRPXgNw4rw6hTmiiBc0DQv48UdasQrU+urSuQRUQrF2LAy/8e//otdM4xC c7xxGBEyHMoBjekU1TPibVbNNQLvgzySAEvrt8tsYjpUwZPyrod/WWDWUj18gzuK6g BHJ3EqzOQgHNNUnQm5Y53KtD93lyf9e900bHUL6g= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Date: Mon, 19 Feb 2018 18:51:35 +0530 From: Abhishek Sahu To: Sricharan R Cc: Andy Gross , Wolfram Sang , David Brown , linux-arm-msm@vger.kernel.org, linux-soc@vger.kernel.org, linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org Subject: Re: [PATCH 11/12] i2c: qup: reorganization of driver code to remove polling for qup v1 In-Reply-To: <04839e54-02bd-b7a6-8a94-26f72c3de7b3@codeaurora.org> References: <1517644697-30806-1-git-send-email-absahu@codeaurora.org> <1517644697-30806-12-git-send-email-absahu@codeaurora.org> <04839e54-02bd-b7a6-8a94-26f72c3de7b3@codeaurora.org> Message-ID: <420a228111f0a71b9d5c3245c42d9148@codeaurora.org> X-Sender: absahu@codeaurora.org User-Agent: Roundcube Webmail/1.2.5 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 2018-02-16 13:14, Sricharan R wrote: > Hi Abhishek, > > On 2/3/2018 1:28 PM, Abhishek Sahu wrote: >> Following are the major issues in current driver code >> >> 1. The current driver simply assumes the transfer completion >> whenever its gets any non-error interrupts and then simply do the >> polling of available/free bytes in FIFO. >> 2. The block mode is not working properly since no handling in >> being done for OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ. >> >> Because of above, i2c v1 transfers of size greater than 32 are failing >> with following error message >> >> i2c_qup 78b6000.i2c: timeout for fifo out full >> >> To make block mode working properly and move to use the interrupts >> instead of polling, major code reorganization is required. Following >> are the major changes done in this patch >> >> 1. Remove the polling of TX FIFO free space and RX FIFO available >> bytes and move to interrupts completely. QUP has >> QUP_MX_OUTPUT_DONE, >> QUP_MX_INPUT_DONE, OUT_BLOCK_WRITE_REQ and IN_BLOCK_READ_REQ >> interrupts to handle FIFO’s properly so check all these interrupts. >> 2. During write, For FIFO mode, TX FIFO can be directly written >> without checking for FIFO space. For block mode, the QUP will >> generate >> OUT_BLOCK_WRITE_REQ interrupt whenever it has block size of >> available >> space. >> 3. During read, both TX and RX FIFO will be used. TX will be used >> for writing tags and RX will be used for receiving the data. In >> QUP, >> TX and RX can operate in separate mode so configure modes >> accordingly. >> 4. For read FIFO mode, wait for QUP_MX_INPUT_DONE interrupt which >> will be generated after all the bytes have been copied in RX FIFO. >> For >> read Block mode, QUP will generate IN_BLOCK_READ_REQ interrupts >> whenever it has block size of available data. >> >> Signed-off-by: Abhishek Sahu >> --- >> drivers/i2c/busses/i2c-qup.c | 399 >> ++++++++++++++++++++++++++++--------------- >> 1 file changed, 257 insertions(+), 142 deletions(-) >> >> diff --git a/drivers/i2c/busses/i2c-qup.c >> b/drivers/i2c/busses/i2c-qup.c >> index edea3b9..af6c21a 100644 >> --- a/drivers/i2c/busses/i2c-qup.c >> +++ b/drivers/i2c/busses/i2c-qup.c >> @@ -73,8 +73,11 @@ >> #define QUP_IN_SVC_FLAG BIT(9) >> #define QUP_MX_OUTPUT_DONE BIT(10) >> #define QUP_MX_INPUT_DONE BIT(11) >> +#define OUT_BLOCK_WRITE_REQ BIT(12) >> +#define IN_BLOCK_READ_REQ BIT(13) >> >> /* I2C mini core related values */ >> +#define QUP_NO_INPUT BIT(7) >> #define QUP_CLOCK_AUTO_GATE BIT(13) >> #define I2C_MINI_CORE (2 << 8) >> #define I2C_N_VAL 15 >> @@ -138,13 +141,51 @@ >> #define DEFAULT_CLK_FREQ 100000 >> #define DEFAULT_SRC_CLK 20000000 >> >> +/* MAX_OUTPUT_DONE_FLAG has been received */ >> +#define QUP_BLK_EVENT_TX_IRQ_DONE BIT(0) >> +/* MAX_INPUT_DONE_FLAG has been received */ >> +#define QUP_BLK_EVENT_RX_IRQ_DONE BIT(1) >> +/* All the TX bytes have been written in TX FIFO */ >> +#define QUP_BLK_EVENT_TX_DATA_DONE BIT(2) >> +/* All the RX bytes have been read from RX FIFO */ >> +#define QUP_BLK_EVENT_RX_DATA_DONE BIT(3) >> + >> +/* All the required events to mark a QUP I2C TX transfer completed */ >> +#define QUP_BLK_EVENT_TX_DONE (QUP_BLK_EVENT_TX_IRQ_DONE | \ >> + QUP_BLK_EVENT_TX_DATA_DONE) >> +/* All the required events to mark a QUP I2C RX transfer completed */ >> +#define QUP_BLK_EVENT_RX_DONE (QUP_BLK_EVENT_TX_DONE | \ >> + QUP_BLK_EVENT_RX_IRQ_DONE | \ >> + QUP_BLK_EVENT_RX_DATA_DONE) >> + >> +/* >> + * count: no of blocks >> + * pos: current block number >> + * tx_tag_len: tx tag length for current block >> + * rx_tag_len: rx tag length for current block >> + * data_len: remaining data length for current message >> + * total_tx_len: total tx length including tag bytes for current QUP >> transfer >> + * total_rx_len: total rx length including tag bytes for current QUP >> transfer >> + * tx_fifo_free: number of free bytes in current QUP block write. >> + * fifo_available: number of available bytes in RX FIFO for current >> + * QUP block read >> + * is_tx_blk_mode: whether tx uses block or FIFO mode in case of non >> BAM xfer. >> + * is_rx_blk_mode: whether rx uses block or FIFO mode in case of non >> BAM xfer. >> + * tags: contains tx tag bytes for current QUP transfer >> + */ >> struct qup_i2c_block { >> - int count; >> - int pos; >> - int tx_tag_len; >> - int rx_tag_len; >> - int data_len; >> - u8 tags[6]; >> + int count; >> + int pos; >> + int tx_tag_len; >> + int rx_tag_len; >> + int data_len; >> + int total_tx_len; >> + int total_rx_len; >> + int tx_fifo_free; >> + int fifo_available; >> + bool is_tx_blk_mode; >> + bool is_rx_blk_mode; >> + u8 tags[6]; >> }; >> >> struct qup_i2c_tag { >> @@ -187,6 +228,7 @@ struct qup_i2c_dev { >> >> /* To check if this is the last msg */ >> bool is_last; >> + bool is_qup_v1; >> >> /* To configure when bus is in run state */ >> int config_run; >> @@ -195,6 +237,10 @@ struct qup_i2c_dev { >> bool is_dma; >> /* To check if the current transfer is using DMA */ >> bool use_dma; >> + /* Required events to mark QUP transfer as completed */ >> + u32 blk_events; >> + /* Already completed events in QUP transfer */ >> + u32 cur_blk_events; >> /* The threshold length above which DMA will be used */ >> unsigned int dma_threshold; >> unsigned int max_xfer_sg_len; >> @@ -205,11 +251,18 @@ struct qup_i2c_dev { >> struct qup_i2c_bam btx; >> >> struct completion xfer; >> + /* function to write data in tx fifo */ >> + void (*write_tx_fifo)(struct qup_i2c_dev *qup); >> + /* function to read data from rx fifo */ >> + void (*read_rx_fifo)(struct qup_i2c_dev *qup); >> + /* function to write tags in tx fifo for i2c read transfer */ >> + void (*write_rx_tags)(struct qup_i2c_dev *qup); >> }; >> >> static irqreturn_t qup_i2c_interrupt(int irq, void *dev) >> { >> struct qup_i2c_dev *qup = dev; >> + struct qup_i2c_block *blk = &qup->blk; >> u32 bus_err; >> u32 qup_err; >> u32 opflags; >> @@ -256,12 +309,54 @@ static irqreturn_t qup_i2c_interrupt(int irq, >> void *dev) >> goto done; >> } >> >> - if (opflags & QUP_IN_SVC_FLAG) >> - writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL); >> + if (!qup->is_qup_v1) >> + goto done; >> >> - if (opflags & QUP_OUT_SVC_FLAG) >> + if (opflags & QUP_OUT_SVC_FLAG) { >> writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL); >> >> + /* >> + * Ideally, would like to check QUP_MAX_OUTPUT_DONE_FLAG. >> + * However, QUP_MAX_OUTPUT_DONE_FLAG is lagging behind >> + * QUP_OUTPUT_SERVICE_FLAG. The only reason for >> + * QUP_OUTPUT_SERVICE_FLAG to be set in FIFO mode is >> + * QUP_MAX_OUTPUT_DONE_FLAG condition. The code checking >> + * here QUP_OUTPUT_SERVICE_FLAG and assumes that >> + * QUP_MAX_OUTPUT_DONE_FLAG. >> + */ >> + if (!blk->is_tx_blk_mode) >> + qup->cur_blk_events |= QUP_BLK_EVENT_TX_IRQ_DONE; >> + >> + if (opflags & OUT_BLOCK_WRITE_REQ) { >> + blk->tx_fifo_free += qup->out_blk_sz; >> + if (qup->msg->flags & I2C_M_RD) >> + qup->write_rx_tags(qup); >> + else >> + qup->write_tx_fifo(qup); >> + } >> + } >> + >> + if (opflags & QUP_IN_SVC_FLAG) { >> + writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL); >> + >> + if (!blk->is_rx_blk_mode) { >> + blk->fifo_available += qup->in_fifo_sz; >> + qup->read_rx_fifo(qup); >> + } else if (opflags & IN_BLOCK_READ_REQ) { >> + blk->fifo_available += qup->in_blk_sz; >> + qup->read_rx_fifo(qup); >> + } >> + } >> + >> + if (opflags & QUP_MX_OUTPUT_DONE) >> + qup->cur_blk_events |= QUP_BLK_EVENT_TX_IRQ_DONE; >> + >> + if (opflags & QUP_MX_INPUT_DONE) >> + qup->cur_blk_events |= QUP_BLK_EVENT_RX_IRQ_DONE; >> + >> + if (qup->cur_blk_events != qup->blk_events) >> + return IRQ_HANDLED; > > Is it correct that if we do a complete in above case, i mean > for TX -> based on QUP_MX_OUTPUT_DONE and for RX -> based on > QUP_MX_INPUT_DONE, would that simplify things by getting rid of > QUP_BLK_EVENT_RX/TX_DONE and QUP_BLK_EVENT_RX/TX_IRQ_DONE > altogether ? We can get rid of QUP_BLK_EVENT_TX_DONE. For RX, the QUP_MX_INPUT_DONE will be triggered when QUP copies all the data in FIFO from external i2c slave. So if 64 bytes read has been scheduled then following is the behaviour IRQ with QUP_MX_INPUT_DONE and IN_BLOCK_READ_REQ -> read 16 bytes IRQ with IN_BLOCK_READ_REQ -> read next 16 bytes IRQ with IN_BLOCK_READ_REQ -> read next 16 bytes IRQ with IN_BLOCK_READ_REQ -> read last 16 bytes So for RX, we can't trigger complete by checking QUP_BLK_EVENT_RX_DONE alone. We need to track the number of bytes read from FIFO. Instead of putting this check, I am taking one extra event bit QUP_BLK_EVENT_RX_DONE which will be set when all the bytes has been read. I am not sure if checking QUP_MX_INPUT_DONE will always work since there may be some case, when for small transfers the QUP_MX_INPUT_DONE will come before QUP_MX_OUTPUT_DONE so checking for both will work always. Thanks, Abhishek