From patchwork Thu Feb 29 18:10:54 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Th=C3=A9o_Lebrun?= X-Patchwork-Id: 208468 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:7301:2097:b0:108:e6aa:91d0 with SMTP id gs23csp587310dyb; Thu, 29 Feb 2024 10:13:29 -0800 (PST) X-Forwarded-Encrypted: i=3; AJvYcCVmBIpJg+xUW+Fn2ma2AcTaIcz4KKg2f3+g4KiEGTe9WRqEYqu5nYJ7uo5yhHIFRYweqyQl7JMEtitA+2gTyyuBSo88Xw== X-Google-Smtp-Source: AGHT+IFYf/Dyk3RNxRJaf4lgZkAubmZQnv7VE8T01IrVDTjFhXMxg7WEVkkULdNNr8njjXX+fFwk X-Received: by 2002:ac8:5c07:0:b0:42e:b0b0:e966 with SMTP id i7-20020ac85c07000000b0042eb0b0e966mr3090125qti.42.1709230409072; Thu, 29 Feb 2024 10:13:29 -0800 (PST) ARC-Seal: i=2; a=rsa-sha256; t=1709230409; cv=pass; d=google.com; s=arc-20160816; b=g27WrctXWHiPrQREI102MnlWWAeoEw/jKlT5UZfMofSxib1Xr49SOSVJRF7yNC68zz bpBBUt5h3nRXkjAV3rOtBZpYvItcONCIYOhDQhHrRVG+ETG5C/zZvVTmqbij4tQ/7Bcv PIQR72dqcobxuiSRfCts+NlgkfgHhwRuY6OT2lYuBUOnvD+MW58C1Q8unzURFVx0xkDe NTTJLmdGQYQxQtT3cRWuDiMazK2+4JZJQwb+KvJuMpa9w+oR6hqPfxt7s9GdhM39DwUp nAnLoLRlfczKSo+5aGkEYZemU+yrUrlnKDWUyf2k8Pa2M6gKORGkxH+As2M2gcS4AO3y vpQQ== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:list-unsubscribe:list-subscribe:list-id:precedence :subject:date:from:dkim-signature; bh=dhbJWAePeOlXAq18CeK+BoWzpOuEusDTkmL/xbVCgow=; fh=5JSnMO1qLgeVtLVJilSQcFnAcZn2MWLSM3RnsAdOnEU=; b=zgrSRWj0qBS8gREzwrQIqAxGNbiNUqMjDv599SM3xt9ZCP94w7UFGxQqwomc6H61Pd m0f3/jZ7vMDUllyKhCzMLf6HW7Z6aC0MyCDBQ6HR/kdnEFH2whylTlcGc96kSe93SpjV DfC6JyyVN86a0yT13DzIfC0bqSStITJivcekJoLEGo3Q585rHsaOiFhUTAqz4vsDJQxq /j/Er4PQGI9/TNji1Ar/2hSSCWOfoANt9TBQnHRVUKdbcDcyj1iBbGBW+vAQpZ5rqBGA wcGqRatmFNcDifbOEt26nbb6jzmyMtIUI50+bueSyobhKb+aYSP/LPEAIXFt9RIFbYeD /kwA==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@bootlin.com header.s=gm1 header.b=Cpk14BfT; arc=pass (i=1 spf=pass spfdomain=bootlin.com dkim=pass dkdomain=bootlin.com dmarc=pass fromdomain=bootlin.com); spf=pass (google.com: domain of linux-kernel+bounces-87247-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-87247-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bootlin.com Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [2604:1380:45d1:ec00::1]) by mx.google.com with ESMTPS id b16-20020ac84f10000000b0042ea48c3bcdsi1696231qte.346.2024.02.29.10.13.28 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Feb 2024 10:13:29 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-87247-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) client-ip=2604:1380:45d1:ec00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@bootlin.com header.s=gm1 header.b=Cpk14BfT; arc=pass (i=1 spf=pass spfdomain=bootlin.com dkim=pass dkdomain=bootlin.com dmarc=pass fromdomain=bootlin.com); spf=pass (google.com: domain of linux-kernel+bounces-87247-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-87247-ouuuleilei=gmail.com@vger.kernel.org"; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bootlin.com Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id BE5BC1C22A2C for ; Thu, 29 Feb 2024 18:13:28 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7D8B81428FC; Thu, 29 Feb 2024 18:11:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="Cpk14BfT" Received: from relay3-d.mail.gandi.net (relay3-d.mail.gandi.net [217.70.183.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BD2FD7A14B; Thu, 29 Feb 2024 18:10:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1709230261; cv=none; b=U2dY8kG727MyqNMUfWDnTx1qxgTzCCtH4ew1w+yMKYKYL2jVdO5f6bHvu1CBkG6AKMBbo/4k5jhSMFWZSTuwx7s7r558XGs5m/hVCzVLCoUEehOkv8IM8dIiCEDpmy2sONZM4p/IQdw/R8gfyGmwkN1cbLu0Gie9p6gT5DXra5o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1709230261; c=relaxed/simple; bh=mP9ABIgXPEmFGqEbjqxNjXtSeS2IMK9lm00xUoVbHRI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=n336SSFiKB8tJiw9UoK8DU7VaC4ayDqgcuTYLn8xbkzWqYiPOwH4FE7zy7ISRC4jhYxVeMJ6DZkfq/OPpAXNiOB/0FU79C2iabDB2R7NZaGUKPlpHUuTbKBpLhrv4on+5lBmCpRZF5LcV5cc0BG8Yjdw5aMrMhkyyuxnRlj2fpQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=Cpk14BfT; arc=none smtp.client-ip=217.70.183.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Received: by mail.gandi.net (Postfix) with ESMTPSA id 4D4C56000C; Thu, 29 Feb 2024 18:10:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1709230257; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dhbJWAePeOlXAq18CeK+BoWzpOuEusDTkmL/xbVCgow=; b=Cpk14BfTCsFsOT/2tbMt0Vk1Ye2bt8g6YUDNumx8MIh2aiob7GdyK7qkaCvlqqEj2ipnIH iKN6jI5I/KE/Rm/n5JZnpRrXFr6uQjlFj3l08/yZuDzSkDlEiV4WxhvamL3IUYefC9mzl5 Gi0EKaaGvlarxBTJ8/pJk3/woOtadfI6z/1W1j+NVIRXBPhrkCoMbx5YmDROX+R7xwYtMT 8I4NA4T4BJDAEFO2tD0k5liRSPVLm2qnGdrCagoYYigkgrRdQYe/wKk4asJDBnwCAO0MWL biPHbX4EFuIjkoFK0C1DiRrj1X7RShSSHXFnWuxsXeKJTdtX5yUJg7sz0gkGGg== From: =?utf-8?q?Th=C3=A9o_Lebrun?= Date: Thu, 29 Feb 2024 19:10:54 +0100 Subject: [PATCH v2 06/11] i2c: nomadik: support short xfer timeouts using waitqueue & hrtimer Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20240229-mbly-i2c-v2-6-b32ed18c098c@bootlin.com> References: <20240229-mbly-i2c-v2-0-b32ed18c098c@bootlin.com> In-Reply-To: <20240229-mbly-i2c-v2-0-b32ed18c098c@bootlin.com> To: Linus Walleij , Andi Shyti , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Thomas Bogendoerfer Cc: linux-arm-kernel@lists.infradead.org, linux-i2c@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mips@vger.kernel.org, Gregory Clement , Vladimir Kondratiev , Thomas Petazzoni , Tawfik Bayouk , =?utf-8?q?Th=C3=A9o_Lebrun?= X-Mailer: b4 0.13.0 X-GND-Sasl: theo.lebrun@bootlin.com X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1792257985339718361 X-GMAIL-MSGID: 1792257985339718361 Replace the completion by a waitqueue for synchronization from IRQ handler to task. For short timeouts, use hrtimers, else use timers. Usecase: avoid blocking the I2C bus for too long when an issue occurs. The threshold picked is one jiffy: if timeout is below that, use hrtimers. This threshold is NOT configurable. Implement behavior but do NOT change fetching of timeout. This means the timeout is unchanged (200ms) and the hrtimer case will never trigger. A waitqueue is used because it supports both desired timeout approaches. See wait_event_timeout() and wait_event_hrtimeout(). An atomic boolean serves as synchronization condition. Reviewed-by: Linus Walleij Signed-off-by: Théo Lebrun Reviewed-by: Wolfram Sang Reviewed-by: Andi Shyti --- drivers/i2c/busses/i2c-nomadik.c | 70 +++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index aa68ab402b10..e68b8e0d7919 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -162,10 +162,11 @@ struct i2c_nmk_client { * @clk_freq: clock frequency for the operation mode * @tft: Tx FIFO Threshold in bytes * @rft: Rx FIFO Threshold in bytes - * @timeout: Slave response timeout (ms) + * @timeout_usecs: Slave response timeout * @sm: speed mode * @stop: stop condition. - * @xfer_complete: acknowledge completion for a I2C message. + * @xfer_wq: xfer done wait queue. + * @xfer_done: xfer done boolean. * @result: controller propogated result. */ struct nmk_i2c_dev { @@ -179,10 +180,11 @@ struct nmk_i2c_dev { u32 clk_freq; unsigned char tft; unsigned char rft; - int timeout; + int timeout_usecs; enum i2c_freq_mode sm; int stop; - struct completion xfer_complete; + struct wait_queue_head xfer_wq; + bool xfer_done; int result; }; @@ -434,6 +436,22 @@ static void setup_i2c_controller(struct nmk_i2c_dev *priv) writel(priv->rft, priv->virtbase + I2C_RFTR); } +static bool nmk_i2c_wait_xfer_done(struct nmk_i2c_dev *priv) +{ + if (priv->timeout_usecs < jiffies_to_usecs(1)) { + unsigned long timeout_usecs = priv->timeout_usecs; + ktime_t timeout = ktime_set(0, timeout_usecs * NSEC_PER_USEC); + + wait_event_hrtimeout(priv->xfer_wq, priv->xfer_done, timeout); + } else { + unsigned long timeout = usecs_to_jiffies(priv->timeout_usecs); + + wait_event_timeout(priv->xfer_wq, priv->xfer_done, timeout); + } + + return priv->xfer_done; +} + /** * read_i2c() - Read from I2C client device * @priv: private data of I2C Driver @@ -445,9 +463,9 @@ static void setup_i2c_controller(struct nmk_i2c_dev *priv) */ static int read_i2c(struct nmk_i2c_dev *priv, u16 flags) { - int status = 0; u32 mcr, irq_mask; - unsigned long timeout; + int status = 0; + bool xfer_done; mcr = load_i2c_mcr_reg(priv, flags); writel(mcr, priv->virtbase + I2C_MCR); @@ -459,7 +477,8 @@ static int read_i2c(struct nmk_i2c_dev *priv, u16 flags) /* enable the controller */ i2c_set_bit(priv->virtbase + I2C_CR, I2C_CR_PE); - init_completion(&priv->xfer_complete); + init_waitqueue_head(&priv->xfer_wq); + priv->xfer_done = false; /* enable interrupts by setting the mask */ irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF | @@ -475,10 +494,9 @@ static int read_i2c(struct nmk_i2c_dev *priv, u16 flags) writel(readl(priv->virtbase + I2C_IMSCR) | irq_mask, priv->virtbase + I2C_IMSCR); - timeout = wait_for_completion_timeout( - &priv->xfer_complete, priv->adap.timeout); + xfer_done = nmk_i2c_wait_xfer_done(priv); - if (timeout == 0) { + if (!xfer_done) { /* Controller timed out */ dev_err(&priv->adev->dev, "read from slave 0x%x timed out\n", priv->cli.slave_adr); @@ -513,9 +531,9 @@ static void fill_tx_fifo(struct nmk_i2c_dev *priv, int no_bytes) */ static int write_i2c(struct nmk_i2c_dev *priv, u16 flags) { - u32 status = 0; u32 mcr, irq_mask; - unsigned long timeout; + u32 status = 0; + bool xfer_done; mcr = load_i2c_mcr_reg(priv, flags); @@ -528,7 +546,8 @@ static int write_i2c(struct nmk_i2c_dev *priv, u16 flags) /* enable the controller */ i2c_set_bit(priv->virtbase + I2C_CR, I2C_CR_PE); - init_completion(&priv->xfer_complete); + init_waitqueue_head(&priv->xfer_wq); + priv->xfer_done = false; /* enable interrupts by settings the masks */ irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR); @@ -554,10 +573,9 @@ static int write_i2c(struct nmk_i2c_dev *priv, u16 flags) writel(readl(priv->virtbase + I2C_IMSCR) | irq_mask, priv->virtbase + I2C_IMSCR); - timeout = wait_for_completion_timeout( - &priv->xfer_complete, priv->adap.timeout); + xfer_done = nmk_i2c_wait_xfer_done(priv); - if (timeout == 0) { + if (!xfer_done) { /* Controller timed out */ dev_err(&priv->adev->dev, "write to slave 0x%x timed out\n", priv->cli.slave_adr); @@ -807,7 +825,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) priv->cli.count); init_hw(priv); } - complete(&priv->xfer_complete); + priv->xfer_done = true; + wake_up(&priv->xfer_wq); + break; @@ -817,7 +837,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) init_hw(priv); i2c_set_bit(priv->virtbase + I2C_ICR, I2C_IT_MAL); - complete(&priv->xfer_complete); + priv->xfer_done = true; + wake_up(&priv->xfer_wq); + break; @@ -834,7 +856,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) init_hw(priv); i2c_set_bit(priv->virtbase + I2C_ICR, I2C_IT_BERR); - complete(&priv->xfer_complete); + priv->xfer_done = true; + wake_up(&priv->xfer_wq); + } break; @@ -848,7 +872,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) init_hw(priv); dev_err(dev, "Tx Fifo Over run\n"); - complete(&priv->xfer_complete); + priv->xfer_done = true; + wake_up(&priv->xfer_wq); + break; @@ -949,7 +975,7 @@ static void nmk_i2c_of_probe(struct device_node *np, priv->sm = I2C_FREQ_MODE_FAST; priv->tft = 1; /* Tx FIFO threshold */ priv->rft = 8; /* Rx FIFO threshold */ - priv->timeout = 200; /* Slave response timeout(ms) */ + priv->timeout_usecs = 200 * USEC_PER_MSEC; /* Slave response timeout */ } static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) @@ -1009,7 +1035,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) adap->owner = THIS_MODULE; adap->class = I2C_CLASS_DEPRECATED; adap->algo = &nmk_i2c_algo; - adap->timeout = msecs_to_jiffies(priv->timeout); + adap->timeout = usecs_to_jiffies(priv->timeout_usecs); snprintf(adap->name, sizeof(adap->name), "Nomadik I2C at %pR", &adev->res);