From patchwork Wed Jan 31 14:16:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Nikula X-Patchwork-Id: 768670 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.15]) (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 2E1377F48F for ; Wed, 31 Jan 2024 14:17:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.15 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706710630; cv=none; b=rzuLdX1ZHIeR6QTJlMAa24igr4Q8jup1ElSdlCcem+uN0TclLOcO2b8eLTbhVayDjCj7e0dpp0MhAn8+rDU1jJ0QZ3aAAitvYdbOfDrnZLCBddt6j0FdjMsWARsHL3HTGNEskmXVLoAd08w3N8md+fjgyFqbktS+jfpUBlnQ/U4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706710630; c=relaxed/simple; bh=akMZVlRhyYPVYCgoLK4kigOX0GhWH89ROyd8cQBrtho=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=L6yA0Au/AKOtuucLZpcp0MJW8W0gWaWTjuZ23M1aX1JRAWUmakDga6C9v4gvzYuAhE9LM223qz9x27Y/KXY+YFkP1O0OZGUcQMMLSVQ3UpBuN9kZgNEIyUvPijbKgz4B8fPOrCTFsqkgcCxPKTWjnXv0VFTD/g1l1ypIekl678A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=J91xAfFS; arc=none smtp.client-ip=198.175.65.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="J91xAfFS" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706710630; x=1738246630; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=akMZVlRhyYPVYCgoLK4kigOX0GhWH89ROyd8cQBrtho=; b=J91xAfFS1UnryejWh85+SVZpmDzbni/6wtABrFtZVOO652rGJeOyLHB6 Uifw808YUz66ILms/FVwhxzdS4rSP8Whm9Sd8VGRJ5aCGRSnO3T8IH9Nh v35ckPHfAyBMshPVUwiSBDypxxoQ0NzzUtV4ud6i5QDp0RD1J5rznCcko rffmQbqd4736tZ3WLnpzj92yjQQ98YnNT6/ZReC9rG5MKP/Hh+JVsgZuD Hj/vDk5ty0s0sEgOPS1sLpqsR2WRwYcRvzQAlhpc6HZnXl3NWjtpoiGiK lqhMhzEEQa/74deCXjB/XPCq4kdS6OT0drnCC8vB4h57nmk6wQndf4ddE g==; X-IronPort-AV: E=McAfee;i="6600,9927,10969"; a="3460453" X-IronPort-AV: E=Sophos;i="6.05,231,1701158400"; d="scan'208";a="3460453" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orvoesa107.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Jan 2024 06:17:09 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10969"; a="788591852" X-IronPort-AV: E=Sophos;i="6.05,231,1701158400"; d="scan'208";a="788591852" Received: from unknown (HELO mylly.fi.intel.com.) ([10.237.72.79]) by orsmga002.jf.intel.com with ESMTP; 31 Jan 2024 06:16:59 -0800 From: Jarkko Nikula To: linux-i2c@vger.kernel.org Cc: Andi Shyti , Andy Shevchenko , Mika Westerberg , Jan Dabros , Jiawen Wu , Sanket Goswami , Basavaraj Natikar , Ruhl, Michael J , Jarkko Nikula Subject: [PATCH 1/6] i2c: designware: Uniform initialization flow for polling mode Date: Wed, 31 Jan 2024 16:16:47 +0200 Message-ID: <20240131141653.2689260-2-jarkko.nikula@linux.intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240131141653.2689260-1-jarkko.nikula@linux.intel.com> References: <20240131141653.2689260-1-jarkko.nikula@linux.intel.com> Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Currently initialization flow in i2c_dw_probe_master() skips a few steps and has code duplication for polling mode implementation. Simplify this by adding a new ACCESS_POLLING flag that is set for those two platforms that currently use polling mode and use it to skip interrupt handler setup. Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-core.h | 1 + drivers/i2c/busses/i2c-designware-master.c | 42 ++++----------------- drivers/i2c/busses/i2c-designware-pcidrv.c | 2 +- drivers/i2c/busses/i2c-designware-platdrv.c | 2 +- 4 files changed, 11 insertions(+), 36 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index a7f6f3eafad7..78c8062a8eb5 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -303,6 +303,7 @@ struct dw_i2c_dev { #define ACCESS_INTR_MASK BIT(0) #define ACCESS_NO_IRQ_SUSPEND BIT(1) #define ARBITRATION_SEMAPHORE BIT(2) +#define ACCESS_POLLING BIT(3) #define MODEL_MSCC_OCELOT BIT(8) #define MODEL_BAIKAL_BT1 BIT(9) diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 85dbd0eb5392..e879a0f5cc97 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -953,31 +953,6 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) return 0; } -static int i2c_dw_poll_adap_quirk(struct dw_i2c_dev *dev) -{ - struct i2c_adapter *adap = &dev->adapter; - int ret; - - pm_runtime_get_noresume(dev->dev); - ret = i2c_add_numbered_adapter(adap); - if (ret) - dev_err(dev->dev, "Failed to add adapter: %d\n", ret); - pm_runtime_put_noidle(dev->dev); - - return ret; -} - -static bool i2c_dw_is_model_poll(struct dw_i2c_dev *dev) -{ - switch (dev->flags & MODEL_MASK) { - case MODEL_AMD_NAVI_GPU: - case MODEL_WANGXUN_SP: - return true; - default: - return false; - } -} - int i2c_dw_probe_master(struct dw_i2c_dev *dev) { struct i2c_adapter *adap = &dev->adapter; @@ -1033,9 +1008,6 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) adap->dev.parent = dev->dev; i2c_set_adapdata(adap, dev); - if (i2c_dw_is_model_poll(dev)) - return i2c_dw_poll_adap_quirk(dev); - if (dev->flags & ACCESS_NO_IRQ_SUSPEND) { irq_flags = IRQF_NO_SUSPEND; } else { @@ -1049,12 +1021,14 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) regmap_write(dev->map, DW_IC_INTR_MASK, 0); i2c_dw_release_lock(dev); - ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags, - dev_name(dev->dev), dev); - if (ret) { - dev_err(dev->dev, "failure requesting irq %i: %d\n", - dev->irq, ret); - return ret; + if (!(dev->flags & ACCESS_POLLING)) { + ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, + irq_flags, dev_name(dev->dev), dev); + if (ret) { + dev_err(dev->dev, "failure requesting irq %i: %d\n", + dev->irq, ret); + return ret; + } } ret = i2c_dw_init_recovery_info(dev); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 61d7a27aa070..9be9a2658e1f 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -154,7 +154,7 @@ static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c) { struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev); - dev->flags |= MODEL_AMD_NAVI_GPU; + dev->flags |= MODEL_AMD_NAVI_GPU | ACCESS_POLLING; dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ; return 0; } diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 855b698e99c0..4ab41ba39d55 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -290,7 +290,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) dev->flags = (uintptr_t)device_get_match_data(&pdev->dev); if (device_property_present(&pdev->dev, "wx,i2c-snps-model")) - dev->flags = MODEL_WANGXUN_SP; + dev->flags = MODEL_WANGXUN_SP | ACCESS_POLLING; dev->dev = &pdev->dev; dev->irq = irq; From patchwork Wed Jan 31 14:16:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Nikula X-Patchwork-Id: 769357 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.15]) (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 245B97F48F for ; Wed, 31 Jan 2024 14:17:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.15 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706710632; cv=none; b=UokapE9304VcqysGtWsPWXLKe7TkaqcoIbPeDLp7Tg9zruMyU0eAuXrYE1UpFz13t/ByNOejvOtfzYmHyB7EhgQ1n+utA02Ww2keheTzheCmKP1pWVJGn2lI4d0hbOojY7ZB5h2Po79jtUrTlCaFrGbqQOcKnpoOE4RhfQXV2dA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706710632; c=relaxed/simple; bh=I1INptr4wTgwgYhDkfo04O8YwbWCb1lkt0P6xrSuK78=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sx79ErvS3LeRYoU+MCOXivPVK4nfAb4Nrhb4Fiv2MdMqYYey8CkZGDhlIrjws5oH6Y0HzGEXvZzJaPvqjMWVR8AUvSbEqzbNs+1Hi3PsuFu4P5e0yGwjrVD9HkNCLK/gJ6OlUn+ahDueRDI9IuMrjr3Q0kHfgMUJ11p0x2oodzs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=dH+u8eJm; arc=none smtp.client-ip=198.175.65.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="dH+u8eJm" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706710632; x=1738246632; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=I1INptr4wTgwgYhDkfo04O8YwbWCb1lkt0P6xrSuK78=; b=dH+u8eJmXeSYC8DGOT6djV3Uviuu4jKJzgBFbRWZlPuD/weQZnEJp2ZV 1gX8a2roozxMIs5EKT2A05+xedbtRD0FRh9zZfr7dmviPv9ZkLnaXXVWu kBRy2y2cRx9KmN3s60tSU7ErniFw7hbDArS7kiUD14g6DmtGddWonN1ow Yeydh8YitakwhEY8QBPA3E2DAiXpkFbsDhV7Qyo/8tARLTkeo5iw3TjsA 0uSd4P+MIUp9cgk6npThZNPJhKHS2bsRUqc3QwmwI14pkqTRr0yvr0wkw glmCqQCB8oHXmcu0gUImxXXSiVp4qMTiVImdjHGzx1M/b1kh2XGyKThC8 A==; X-IronPort-AV: E=McAfee;i="6600,9927,10969"; a="3460462" X-IronPort-AV: E=Sophos;i="6.05,231,1701158400"; d="scan'208";a="3460462" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orvoesa107.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Jan 2024 06:17:11 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10969"; a="788591869" X-IronPort-AV: E=Sophos;i="6.05,231,1701158400"; d="scan'208";a="788591869" Received: from unknown (HELO mylly.fi.intel.com.) ([10.237.72.79]) by orsmga002.jf.intel.com with ESMTP; 31 Jan 2024 06:17:06 -0800 From: Jarkko Nikula To: linux-i2c@vger.kernel.org Cc: Andi Shyti , Andy Shevchenko , Mika Westerberg , Jan Dabros , Jiawen Wu , Sanket Goswami , Basavaraj Natikar , Ruhl, Michael J , Jarkko Nikula Subject: [PATCH 2/6] i2c: designware: Do not enable interrupts shortly in polling mode Date: Wed, 31 Jan 2024 16:16:48 +0200 Message-ID: <20240131141653.2689260-3-jarkko.nikula@linux.intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240131141653.2689260-1-jarkko.nikula@linux.intel.com> References: <20240131141653.2689260-1-jarkko.nikula@linux.intel.com> Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 I was testing the polling mode txgbe_i2c_dw_xfer_quirk() on a HW where the i2c-designware has interrupt connected and shared with other device. I noticed there is a bogus interrupt for each transfer. Reason for this that both polling mode functions call the i2c_dw_xfer_init() which enable interrupts then followed by immediate disable by the same polling mode functions. This is enough to trigger TX_EMPTY interrupt. Fix this by introducing a __i2c_dw_write_intr_mask() helper that unmasks interrupts conditionally and use it in i2c_dw_xfer_init(). Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-core.h | 8 ++++++++ drivers/i2c/busses/i2c-designware-master.c | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 78c8062a8eb5..8ce6111cdda3 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -352,6 +352,14 @@ static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev) dev->status &= ~STATUS_ACTIVE; } +static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev, + unsigned int intr_mask) +{ + unsigned int val = dev->flags & ACCESS_POLLING ? 0 : intr_mask; + + regmap_write(dev->map, DW_IC_INTR_MASK, val); +} + void __i2c_dw_disable(struct dw_i2c_dev *dev); extern void i2c_dw_configure_master(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index e879a0f5cc97..835d82e2c5fe 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -250,7 +250,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) /* Clear and enable interrupts */ regmap_read(dev->map, DW_IC_CLR_INTR, &dummy); - regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK); + __i2c_dw_write_intr_mask(dev, DW_IC_INTR_MASTER_MASK); } static int i2c_dw_check_stopbit(struct dw_i2c_dev *dev) @@ -300,7 +300,6 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, dev->msgs = msgs; dev->msgs_num = num_msgs; i2c_dw_xfer_init(dev); - regmap_write(dev->map, DW_IC_INTR_MASK, 0); /* Initiate messages read/write transaction */ for (msg_wrt_idx = 0; msg_wrt_idx < num_msgs; msg_wrt_idx++) { @@ -384,7 +383,6 @@ static int txgbe_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msg dev->msgs = msgs; dev->msgs_num = num_msgs; i2c_dw_xfer_init(dev); - regmap_write(dev->map, DW_IC_INTR_MASK, 0); for (msg_idx = 0; msg_idx < num_msgs; msg_idx++) { buf = msgs[msg_idx].buf; From patchwork Wed Jan 31 14:16:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Nikula X-Patchwork-Id: 768669 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.15]) (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 72CD87F488 for ; Wed, 31 Jan 2024 14:17:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.15 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706710637; cv=none; b=gDku5yD25Es3hRHdwQukoN4PmBBoCYW4y4bR4HqEPj0aO9L9LbTxVcajZzbKa7JM0Rx7E8qJdyh0VG/xWUO/ava37J3sXnCLSgw+cuLE6BVbCc8fVNb4+qpyI8WEOQSsSZvmyRVAem3+JaLyNeUYroSzY+qL0VfJ4BR6pGATlmE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706710637; c=relaxed/simple; bh=CCOkECtyYC7+84Htb6YkffVn0zFMf6Enor5lfqSj8IU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XE/MdAGAG5fKrP8IfcXofwuCALcIpwNq6b5OCLuTKC1j+q0WuqEaZPPCOfInTpp8EY7+6qUdBnp/R9mSdqIuewx7YGDTrmAF8wza+YvKKNyIQhYwV5q9DPdyrcy2zierR9ZmHJS9o55O8kzzdB9rtEE2mrP5UTZxRD0zum0xXW8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=PaTUkz8L; arc=none smtp.client-ip=198.175.65.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="PaTUkz8L" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706710636; x=1738246636; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=CCOkECtyYC7+84Htb6YkffVn0zFMf6Enor5lfqSj8IU=; b=PaTUkz8LDhlHkcNgtINdMW0pQGo/N40PMs95H4ERIr3fifnOukVGihvh 9kUg+HYbM+HT+RQ089xT6Nyj+4KlN06Y2oppyhl0lORikGWjSSTBvT98J 1/36eH3uf1gwWyQE0OH/TTH0986uwlt8kS1DHJ8A8w8KshntqE5aYJlUL 0TZCgjcb0lwYL8XxkX7OHVB15m7nJP72DQVu5mcbMMUYqTaA8AnOFLCT9 f5YOILWb0LwZ0/7LHXcUI3SOyi3lnghEKQJ06Ny0EhM1GXWdzC23g19TP aLpnGe7ZzSWCcT6CkoF+4pdl/x7lzt5kV0IRgzX2fDr+Bfn0m+E/RoG0L Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10969"; a="3460474" X-IronPort-AV: E=Sophos;i="6.05,231,1701158400"; d="scan'208";a="3460474" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orvoesa107.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Jan 2024 06:17:16 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10969"; a="788591887" X-IronPort-AV: E=Sophos;i="6.05,231,1701158400"; d="scan'208";a="788591887" Received: from unknown (HELO mylly.fi.intel.com.) ([10.237.72.79]) by orsmga002.jf.intel.com with ESMTP; 31 Jan 2024 06:17:11 -0800 From: Jarkko Nikula To: linux-i2c@vger.kernel.org Cc: Andi Shyti , Andy Shevchenko , Mika Westerberg , Jan Dabros , Jiawen Wu , Sanket Goswami , Basavaraj Natikar , Ruhl, Michael J , Jarkko Nikula Subject: [PATCH 3/6] i2c: designware: Use accessors to DW_IC_INTR_MASK register Date: Wed, 31 Jan 2024 16:16:49 +0200 Message-ID: <20240131141653.2689260-4-jarkko.nikula@linux.intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240131141653.2689260-1-jarkko.nikula@linux.intel.com> References: <20240131141653.2689260-1-jarkko.nikula@linux.intel.com> Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Convert access to DW_IC_INTR_MASK register using the existing __i2c_dw_write_intr_mask() and a __i2c_dw_read_intr_mask() introduced here. Motivation to this is to prepare for generic polling mode code where polling mode will use a SW mask instead of DW_IC_INTR_MASK. Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-common.c | 2 +- drivers/i2c/busses/i2c-designware-core.h | 7 +++++++ drivers/i2c/busses/i2c-designware-master.c | 22 ++++++++++++---------- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 35f762872b8a..e8a688d04aee 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -648,7 +648,7 @@ void i2c_dw_disable(struct dw_i2c_dev *dev) __i2c_dw_disable(dev); /* Disable all interrupts */ - regmap_write(dev->map, DW_IC_INTR_MASK, 0); + __i2c_dw_write_intr_mask(dev, 0); regmap_read(dev->map, DW_IC_CLR_INTR, &dummy); i2c_dw_release_lock(dev); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 8ce6111cdda3..4d277ebcca92 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -360,6 +360,13 @@ static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev, regmap_write(dev->map, DW_IC_INTR_MASK, val); } +static inline void __i2c_dw_read_intr_mask(struct dw_i2c_dev *dev, + unsigned int *intr_mask) +{ + if (!(dev->flags & ACCESS_POLLING)) + regmap_read(dev->map, DW_IC_INTR_MASK, intr_mask); +} + void __i2c_dw_disable(struct dw_i2c_dev *dev); extern void i2c_dw_configure_master(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 835d82e2c5fe..2e8f9733ddd3 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -240,7 +240,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) msgs[dev->msg_write_idx].addr | ic_tar); /* Enforce disabled interrupts (due to HW issues) */ - regmap_write(dev->map, DW_IC_INTR_MASK, 0); + __i2c_dw_write_intr_mask(dev, 0); /* Enable the adapter */ __i2c_dw_enable(dev); @@ -544,7 +544,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) if (dev->msg_err) intr_mask = 0; - regmap_write(dev->map, DW_IC_INTR_MASK, intr_mask); + __i2c_dw_write_intr_mask(dev, intr_mask); } static u8 @@ -552,6 +552,7 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len) { struct i2c_msg *msgs = dev->msgs; u32 flags = msgs[dev->msg_read_idx].flags; + unsigned int intr_mask; /* * Adjust the buffer length and mask the flag @@ -566,8 +567,9 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len) * Received buffer length, re-enable TX_EMPTY interrupt * to resume the SMBUS transaction. */ - regmap_update_bits(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_TX_EMPTY, - DW_IC_INTR_TX_EMPTY); + __i2c_dw_read_intr_mask(dev, &intr_mask); + intr_mask |= DW_IC_INTR_TX_EMPTY; + __i2c_dw_write_intr_mask(dev, intr_mask); return len; } @@ -827,7 +829,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) * interrupt really came from this HW (E.g. firmware has left * the HW active). */ - regmap_write(dev->map, DW_IC_INTR_MASK, 0); + __i2c_dw_write_intr_mask(dev, 0); return IRQ_HANDLED; } @@ -840,7 +842,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) * Anytime TX_ABRT is set, the contents of the tx/rx * buffers are flushed. Make sure to skip them. */ - regmap_write(dev->map, DW_IC_INTR_MASK, 0); + __i2c_dw_write_intr_mask(dev, 0); goto tx_aborted; } @@ -862,9 +864,9 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) complete(&dev->cmd_complete); else if (unlikely(dev->flags & ACCESS_INTR_MASK)) { /* Workaround to trigger pending interrupt */ - regmap_read(dev->map, DW_IC_INTR_MASK, &stat); - regmap_write(dev->map, DW_IC_INTR_MASK, 0); - regmap_write(dev->map, DW_IC_INTR_MASK, stat); + __i2c_dw_read_intr_mask(dev, &stat); + __i2c_dw_write_intr_mask(dev, 0); + __i2c_dw_write_intr_mask(dev, stat); } return IRQ_HANDLED; @@ -1016,7 +1018,7 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) if (ret) return ret; - regmap_write(dev->map, DW_IC_INTR_MASK, 0); + __i2c_dw_write_intr_mask(dev, 0); i2c_dw_release_lock(dev); if (!(dev->flags & ACCESS_POLLING)) { From patchwork Wed Jan 31 14:16:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Nikula X-Patchwork-Id: 769356 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.15]) (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 80CD180C1D for ; Wed, 31 Jan 2024 14:17:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.15 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706710641; cv=none; b=jH6FlN2gqNS2Rxxqzv8yt9Q6AIuttaE/NiDwhpnoe6Gi0V94uMILrEi0LF8FTnb/+pimGzulQPeF02zK77qomL25GhbakMmc3UpXARIma6EBt3L3vhqzSH3xZJxtIV0rWO/7LdEC0rWwBDANqsja1OBq1LI1fC1/HpocXosPgYM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706710641; c=relaxed/simple; bh=UoiwHy7xqEgMy8eOAK4q8jh0JHOFwvCIB7tA/aMNWu8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EXPy4dJ3fHEl7TawsVNt+uLFGc2vou8ZXDg1Ix3G2J7edkaME0re3v2y1CzBRmISKAaN05KAilcFh8b7JXmhoR+jq2GmQQBKtsqQZ5og4EFH7vp6tnKC2UzBZHpSJUHDRG5U2wK0d7HEQyHmRjA8MpD8X+x86r3GApKNsNgLz88= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=QhnrsEsd; arc=none smtp.client-ip=198.175.65.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="QhnrsEsd" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706710640; x=1738246640; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=UoiwHy7xqEgMy8eOAK4q8jh0JHOFwvCIB7tA/aMNWu8=; b=QhnrsEsdI3h2DTvh8JoBM11RYtlFasdm1lFy8UL1xTC6aiw6K0vdNSci 7ScQQwoHvoqGvnzRyS87pmxdQeoEj3udDznZv+3KBMF6JoHzFUV4+UZeU JjDCAZgk9c+T2Ikc6sZ3H80bsWHbZ+n6wasvjn8SJZuatx1Ml5JC97UxJ 03up3LeqeSkwzPj04jx4muLXvwU1lPaI2AEmA7Uni3F0uBgLZBHVSWYBq j4D0ZSxOb+pGGiCz7yTYbei4YIWA8WPImwU6nGBCbFb5G/tQMjuW92YiW kV52FMS7CfsPSYShYirkC5NhT3VMLq6Dz0wPYdqvsuMbxCnrnvvGlHsAV A==; X-IronPort-AV: E=McAfee;i="6600,9927,10969"; a="3460485" X-IronPort-AV: E=Sophos;i="6.05,231,1701158400"; d="scan'208";a="3460485" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orvoesa107.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Jan 2024 06:17:20 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10969"; a="788591904" X-IronPort-AV: E=Sophos;i="6.05,231,1701158400"; d="scan'208";a="788591904" Received: from unknown (HELO mylly.fi.intel.com.) ([10.237.72.79]) by orsmga002.jf.intel.com with ESMTP; 31 Jan 2024 06:17:15 -0800 From: Jarkko Nikula To: linux-i2c@vger.kernel.org Cc: Andi Shyti , Andy Shevchenko , Mika Westerberg , Jan Dabros , Jiawen Wu , Sanket Goswami , Basavaraj Natikar , Ruhl, Michael J , Jarkko Nikula Subject: [PATCH 4/6] i2c: designware: Move interrupt handling functions before i2c_dw_xfer() Date: Wed, 31 Jan 2024 16:16:50 +0200 Message-ID: <20240131141653.2689260-5-jarkko.nikula@linux.intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240131141653.2689260-1-jarkko.nikula@linux.intel.com> References: <20240131141653.2689260-1-jarkko.nikula@linux.intel.com> Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Code is more logically arranged when i2c_dw_read_clear_intrbits() and i2c_dw_isr() are located before i2c_dw_xfer(). Real reason for this is to prepare for more shared code between interrupt and polling mode code. Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-master.c | 226 ++++++++++----------- 1 file changed, 113 insertions(+), 113 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 2e8f9733ddd3..856c955c6560 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -633,119 +633,6 @@ i2c_dw_read(struct dw_i2c_dev *dev) } } -/* - * Prepare controller for a transaction and call i2c_dw_xfer_msg. - */ -static int -i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) -{ - struct dw_i2c_dev *dev = i2c_get_adapdata(adap); - int ret; - - dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); - - pm_runtime_get_sync(dev->dev); - - /* - * Initiate I2C message transfer when polling mode is enabled, - * As it is polling based transfer mechanism, which does not support - * interrupt based functionalities of existing DesignWare driver. - */ - switch (dev->flags & MODEL_MASK) { - case MODEL_AMD_NAVI_GPU: - ret = amd_i2c_dw_xfer_quirk(adap, msgs, num); - goto done_nolock; - case MODEL_WANGXUN_SP: - ret = txgbe_i2c_dw_xfer_quirk(adap, msgs, num); - goto done_nolock; - default: - break; - } - - reinit_completion(&dev->cmd_complete); - dev->msgs = msgs; - dev->msgs_num = num; - dev->cmd_err = 0; - dev->msg_write_idx = 0; - dev->msg_read_idx = 0; - dev->msg_err = 0; - dev->status = 0; - dev->abort_source = 0; - dev->rx_outstanding = 0; - - ret = i2c_dw_acquire_lock(dev); - if (ret) - goto done_nolock; - - ret = i2c_dw_wait_bus_not_busy(dev); - if (ret < 0) - goto done; - - /* Start the transfers */ - i2c_dw_xfer_init(dev); - - /* Wait for tx to complete */ - if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { - dev_err(dev->dev, "controller timed out\n"); - /* i2c_dw_init implicitly disables the adapter */ - i2c_recover_bus(&dev->adapter); - i2c_dw_init_master(dev); - ret = -ETIMEDOUT; - goto done; - } - - /* - * We must disable the adapter before returning and signaling the end - * of the current transfer. Otherwise the hardware might continue - * generating interrupts which in turn causes a race condition with - * the following transfer. Needs some more investigation if the - * additional interrupts are a hardware bug or this driver doesn't - * handle them correctly yet. - */ - __i2c_dw_disable_nowait(dev); - - if (dev->msg_err) { - ret = dev->msg_err; - goto done; - } - - /* No error */ - if (likely(!dev->cmd_err && !dev->status)) { - ret = num; - goto done; - } - - /* We have an error */ - if (dev->cmd_err == DW_IC_ERR_TX_ABRT) { - ret = i2c_dw_handle_tx_abort(dev); - goto done; - } - - if (dev->status) - dev_err(dev->dev, - "transfer terminated early - interrupt latency too high?\n"); - - ret = -EIO; - -done: - i2c_dw_release_lock(dev); - -done_nolock: - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); - - return ret; -} - -static const struct i2c_algorithm i2c_dw_algo = { - .master_xfer = i2c_dw_xfer, - .functionality = i2c_dw_func, -}; - -static const struct i2c_adapter_quirks i2c_dw_quirks = { - .flags = I2C_AQ_NO_ZERO_LEN, -}; - static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) { unsigned int stat, dummy; @@ -872,6 +759,119 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) return IRQ_HANDLED; } +/* + * Prepare controller for a transaction and call i2c_dw_xfer_msg. + */ +static int +i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + int ret; + + dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); + + pm_runtime_get_sync(dev->dev); + + /* + * Initiate I2C message transfer when polling mode is enabled, + * As it is polling based transfer mechanism, which does not support + * interrupt based functionalities of existing DesignWare driver. + */ + switch (dev->flags & MODEL_MASK) { + case MODEL_AMD_NAVI_GPU: + ret = amd_i2c_dw_xfer_quirk(adap, msgs, num); + goto done_nolock; + case MODEL_WANGXUN_SP: + ret = txgbe_i2c_dw_xfer_quirk(adap, msgs, num); + goto done_nolock; + default: + break; + } + + reinit_completion(&dev->cmd_complete); + dev->msgs = msgs; + dev->msgs_num = num; + dev->cmd_err = 0; + dev->msg_write_idx = 0; + dev->msg_read_idx = 0; + dev->msg_err = 0; + dev->status = 0; + dev->abort_source = 0; + dev->rx_outstanding = 0; + + ret = i2c_dw_acquire_lock(dev); + if (ret) + goto done_nolock; + + ret = i2c_dw_wait_bus_not_busy(dev); + if (ret < 0) + goto done; + + /* Start the transfers */ + i2c_dw_xfer_init(dev); + + /* Wait for tx to complete */ + if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { + dev_err(dev->dev, "controller timed out\n"); + /* i2c_dw_init implicitly disables the adapter */ + i2c_recover_bus(&dev->adapter); + i2c_dw_init_master(dev); + ret = -ETIMEDOUT; + goto done; + } + + /* + * We must disable the adapter before returning and signaling the end + * of the current transfer. Otherwise the hardware might continue + * generating interrupts which in turn causes a race condition with + * the following transfer. Needs some more investigation if the + * additional interrupts are a hardware bug or this driver doesn't + * handle them correctly yet. + */ + __i2c_dw_disable_nowait(dev); + + if (dev->msg_err) { + ret = dev->msg_err; + goto done; + } + + /* No error */ + if (likely(!dev->cmd_err && !dev->status)) { + ret = num; + goto done; + } + + /* We have an error */ + if (dev->cmd_err == DW_IC_ERR_TX_ABRT) { + ret = i2c_dw_handle_tx_abort(dev); + goto done; + } + + if (dev->status) + dev_err(dev->dev, + "transfer terminated early - interrupt latency too high?\n"); + + ret = -EIO; + +done: + i2c_dw_release_lock(dev); + +done_nolock: + pm_runtime_mark_last_busy(dev->dev); + pm_runtime_put_autosuspend(dev->dev); + + return ret; +} + +static const struct i2c_algorithm i2c_dw_algo = { + .master_xfer = i2c_dw_xfer, + .functionality = i2c_dw_func, +}; + +static const struct i2c_adapter_quirks i2c_dw_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN, +}; + void i2c_dw_configure_master(struct dw_i2c_dev *dev) { struct i2c_timings *t = &dev->timings; From patchwork Wed Jan 31 14:16:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jarkko Nikula X-Patchwork-Id: 768668 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.15]) (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 84A0B7F48F for ; Wed, 31 Jan 2024 14:17:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.15 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706710645; cv=none; b=ta5Bpa/V3lXBgKtXqPbLO34jqaElEh3I6CtbRrrbKWUZCKCPtgtTGphnp4gJrd5eKBdooBPnD482GM6arlpwLXrIAxscHgFlgYmtgyxzo4PIU+9Zco2E7aQXvdkQRGMHvK91T1k9I1EVsgK4ZGPmXSEf5mFcH488J10XoPAFQY4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706710645; c=relaxed/simple; bh=1aKDNz7zbM0I5hek9PLCcgd8MCkmbiz3Mn3zShsxDso=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ISYMaYROIn6LpahTG7awnx36acIaQIjhR5zam85r4mTPdBbYV9ur2GhjG7ExyXNuU6/IYp878Ox5m6Xn1MaQEjkC6PRaVwZOdGS/wrsuVGM3O3PPKr+FNSAt5M7/BKbdx7XU/V4VZkAP2XRY4Kounhoa0POb8DdNPhEfMQQ5v/M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=V60nfjsf; arc=none smtp.client-ip=198.175.65.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="V60nfjsf" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706710644; x=1738246644; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=1aKDNz7zbM0I5hek9PLCcgd8MCkmbiz3Mn3zShsxDso=; b=V60nfjsfCfE1HgEBvAP6BPpFEWA2PA/ESlGgaqxi9kVi45Ljh8OW0W8G XvyHwkvMhRGCUPIalc9reUfCSn+PgXWrS435HccgL3W3TK0BUDI8Qkry6 x8gPpKL/VCnHRhvsTQo05rCpX4VKjA+PAToUP93MuM5inaliazSO1VyYm g19K11O8nL1mJ6QEkzK8UbgM3xtRLD8V6wqxmywiH7oUbQEzZincevN0a SCrqGyGrSODVq/kGhs7wQM/MqJUWl6TX9bZML5Bwjw4059Uwi9Ds0XChL +zfK/qrWthFyaA2c7osgfIB0j31I0NhA0zpEKjLxgWNs/hTNDsbbR2+Vw A==; X-IronPort-AV: E=McAfee;i="6600,9927,10969"; a="3460493" X-IronPort-AV: E=Sophos;i="6.05,231,1701158400"; d="scan'208";a="3460493" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orvoesa107.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Jan 2024 06:17:24 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10969"; a="788591920" X-IronPort-AV: E=Sophos;i="6.05,231,1701158400"; d="scan'208";a="788591920" Received: from unknown (HELO mylly.fi.intel.com.) ([10.237.72.79]) by orsmga002.jf.intel.com with ESMTP; 31 Jan 2024 06:17:19 -0800 From: Jarkko Nikula To: linux-i2c@vger.kernel.org Cc: Andi Shyti , Andy Shevchenko , Mika Westerberg , Jan Dabros , Jiawen Wu , Sanket Goswami , Basavaraj Natikar , Ruhl, Michael J , Jarkko Nikula Subject: [PATCH 5/6] i2c: designware: Fix RX FIFO depth define on Wangxun 10Gb NIC Date: Wed, 31 Jan 2024 16:16:51 +0200 Message-ID: <20240131141653.2689260-6-jarkko.nikula@linux.intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240131141653.2689260-1-jarkko.nikula@linux.intel.com> References: <20240131141653.2689260-1-jarkko.nikula@linux.intel.com> Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 I believe RX FIFO depth define 0 is incorrect on Wangxun 10Gb NIC. It must be at least 1 since code is able to read received data from the DW_IC_DATA_CMD register. For now this define is irrelevant since the txgbe_i2c_dw_xfer_quirk() doesn't use the rx_fifo_depth member variable of struct dw_i2c_dev but is needed when converting code into generic polling mode implementation. Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 4d277ebcca92..bf8f140dc113 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -319,7 +319,7 @@ struct dw_i2c_dev { #define AMD_UCSI_INTR_EN 0xd #define TXGBE_TX_FIFO_DEPTH 4 -#define TXGBE_RX_FIFO_DEPTH 0 +#define TXGBE_RX_FIFO_DEPTH 1 struct i2c_dw_semaphore_callbacks { int (*probe)(struct dw_i2c_dev *dev); From patchwork Wed Jan 31 14:16:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jarkko Nikula X-Patchwork-Id: 768667 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.15]) (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 D7EF680C17 for ; Wed, 31 Jan 2024 14:17:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.15 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706710653; cv=none; b=ubLJUYURWBbGW/OujSg/viekeYA6Pza15HtWdB2qTcY04T4uOUFc3cZeaSKtiQ7v6W+N2NMbvRuQSjSB97hVHyarkKFee+NNjWJiOTwN2GoDmOrlxg6Y35dJEX660ClGfJALq9iPqBUCr6tfkYSZdhmwpxERdduKDftQr9SbW/Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706710653; c=relaxed/simple; bh=RdqHBLXdlNXGS95R6Ht1b8gMBIQhxiEdF+Iv9N6/kpY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=QE/CwXJIftZ1W+CVU4Xb4Fxjmchzks3DE8qgiZuLGWsVmc04xiaX3FMn5jn4rO2uNuIHA/7DwZD1elMVdDXxvJ0Jt9P0w48gAE4ugTmoa6vzd+W0u0BRAYx+I/Mro8kIFDOAeTaF9I6vUrxvEYQkFg2fJhnA/31RO0KSaWh6uaQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=NTCQoCjI; arc=none smtp.client-ip=198.175.65.15 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="NTCQoCjI" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1706710652; x=1738246652; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=RdqHBLXdlNXGS95R6Ht1b8gMBIQhxiEdF+Iv9N6/kpY=; b=NTCQoCjIHGwkr8iyPBdciJWlqxdpoUWpCGqLBUk0JCXuwr6vQZyB0eAZ OQ64xc5beSt2k356FONbrBNFWkINnchdjgN5RZD6f8a0FlHhBAlZi6BBt IuvrNo/K1liWfbaKhj+snh594O9r9AFo2WLRzQRYidFP3kg0H8BWQfBq/ uv8SjtpdgP4FPGmH22o7+2QfpKRivEVW7jZUKDbbrUJCH+ZJecaQS9CYM IEmGCJSCS+k0RkOOYILtk8jPKWzv4CPkYmdA254aBrvZ31Ffba8TuALha Ru7MR0RS42slggei8H6GxP2B4lrXf6qPQZVnUuQBfait2vty72JEiARf0 g==; X-IronPort-AV: E=McAfee;i="6600,9927,10969"; a="3460536" X-IronPort-AV: E=Sophos;i="6.05,231,1701158400"; d="scan'208";a="3460536" Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orvoesa107.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 31 Jan 2024 06:17:32 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10969"; a="788591948" X-IronPort-AV: E=Sophos;i="6.05,231,1701158400"; d="scan'208";a="788591948" Received: from unknown (HELO mylly.fi.intel.com.) ([10.237.72.79]) by orsmga002.jf.intel.com with ESMTP; 31 Jan 2024 06:17:27 -0800 From: Jarkko Nikula To: linux-i2c@vger.kernel.org Cc: Andi Shyti , Andy Shevchenko , Mika Westerberg , Jan Dabros , Jiawen Wu , Sanket Goswami , Basavaraj Natikar , Ruhl, Michael J , Jarkko Nikula Subject: [PATCH 6/6] i2c: designware: Implement generic polling mode code for Wangxun 10Gb NIC Date: Wed, 31 Jan 2024 16:16:53 +0200 Message-ID: <20240131141653.2689260-8-jarkko.nikula@linux.intel.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240131141653.2689260-1-jarkko.nikula@linux.intel.com> References: <20240131141653.2689260-1-jarkko.nikula@linux.intel.com> Precedence: bulk X-Mailing-List: linux-i2c@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 I got an idea the i2c-designware should not need duplicated state machines for the interrupt and polling modes. The IP is practically the same and state transitions happens in response to the events that can be observed from the DW_IC_RAW_INTR_STAT register. Either by interrupts or by polling. Another reasons are the interrupt mode is the most tested, has handling for special cases as well as transmit abort handling and those are missing from two polling mode quirks. Patch implements a generic polling mode by using existing code for interrupt mode. This is done by moving event handling from the i2c_dw_isr() into a new i2c_dw_process_transfer() that will be called both from the i2c_dw_isr() and a polling loop. Polling loop is implemented in a new i2c_dw_wait_transfer() that is shared between both modes. In interrupt mode it waits for the completion object as before. In polling mode both completion object and DW_IC_RAW_INTR_STAT are polled to determine completed transfer and state transitions. Loop tries to save power by sleeping "stetson guessed" range between 3 and 25 µS which falls between 10 cycles of High-speed mode 3.4 Mb/s and Fast mode 400 kHz. With it the CPU usage was reduced under heavy Fast mode I2C transfer without much increase in total transfer time but otherwise no more effort has been put to optimize this. I decided to convert the txgbe_i2c_dw_xfer_quirk() straight to generic polling mode code in this patch. It doesn't have HW dependent quirks like the amd_i2c_dw_xfer_quirk() does have and without users this patch is needless. Signed-off-by: Jarkko Nikula --- drivers/i2c/busses/i2c-designware-core.h | 5 + drivers/i2c/busses/i2c-designware-master.c | 169 +++++++++------------ 2 files changed, 77 insertions(+), 97 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index bf8f140dc113..e9606c00b8d1 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -212,6 +212,7 @@ struct reset_control; * @msg_err: error status of the current transfer * @status: i2c master status, one of STATUS_* * @abort_source: copy of the TX_ABRT_SOURCE register + * @sw_mask: SW mask of DW_IC_INTR_MASK used in polling mode * @irq: interrupt number for the i2c master * @flags: platform specific flags like type of IO accessors or model * @adapter: i2c subsystem adapter node @@ -270,6 +271,7 @@ struct dw_i2c_dev { int msg_err; unsigned int status; unsigned int abort_source; + unsigned int sw_mask; int irq; u32 flags; struct i2c_adapter adapter; @@ -358,6 +360,7 @@ static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev, unsigned int val = dev->flags & ACCESS_POLLING ? 0 : intr_mask; regmap_write(dev->map, DW_IC_INTR_MASK, val); + dev->sw_mask = intr_mask; } static inline void __i2c_dw_read_intr_mask(struct dw_i2c_dev *dev, @@ -365,6 +368,8 @@ static inline void __i2c_dw_read_intr_mask(struct dw_i2c_dev *dev, { if (!(dev->flags & ACCESS_POLLING)) regmap_read(dev->map, DW_IC_INTR_MASK, intr_mask); + else + *intr_mask = dev->sw_mask; } void __i2c_dw_disable(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 856c955c6560..5897fad544c0 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -354,67 +354,6 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, return 0; } -static int i2c_dw_poll_tx_empty(struct dw_i2c_dev *dev) -{ - u32 val; - - return regmap_read_poll_timeout(dev->map, DW_IC_RAW_INTR_STAT, val, - val & DW_IC_INTR_TX_EMPTY, - 100, 1000); -} - -static int i2c_dw_poll_rx_full(struct dw_i2c_dev *dev) -{ - u32 val; - - return regmap_read_poll_timeout(dev->map, DW_IC_RAW_INTR_STAT, val, - val & DW_IC_INTR_RX_FULL, - 100, 1000); -} - -static int txgbe_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num_msgs) -{ - struct dw_i2c_dev *dev = i2c_get_adapdata(adap); - int msg_idx, buf_len, data_idx, ret; - unsigned int val, stop = 0; - u8 *buf; - - dev->msgs = msgs; - dev->msgs_num = num_msgs; - i2c_dw_xfer_init(dev); - - for (msg_idx = 0; msg_idx < num_msgs; msg_idx++) { - buf = msgs[msg_idx].buf; - buf_len = msgs[msg_idx].len; - - for (data_idx = 0; data_idx < buf_len; data_idx++) { - if (msg_idx == num_msgs - 1 && data_idx == buf_len - 1) - stop |= BIT(9); - - if (msgs[msg_idx].flags & I2C_M_RD) { - regmap_write(dev->map, DW_IC_DATA_CMD, 0x100 | stop); - - ret = i2c_dw_poll_rx_full(dev); - if (ret) - return ret; - - regmap_read(dev->map, DW_IC_DATA_CMD, &val); - buf[data_idx] = val; - } else { - ret = i2c_dw_poll_tx_empty(dev); - if (ret) - return ret; - - regmap_write(dev->map, DW_IC_DATA_CMD, - buf[data_idx] | stop); - } - } - } - - return num_msgs; -} - /* * Initiate (and continue) low level master read/write transaction. * This function is only called from i2c_dw_isr, and pumping i2c_msg @@ -649,7 +588,12 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) * * The raw version might be useful for debugging purposes. */ - regmap_read(dev->map, DW_IC_INTR_STAT, &stat); + if (!(dev->flags & ACCESS_POLLING)) { + regmap_read(dev->map, DW_IC_INTR_STAT, &stat); + } else { + regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat); + stat &= dev->sw_mask; + } /* * Do not use the IC_CLR_INTR register to clear interrupts, or @@ -689,37 +633,8 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) return stat; } -/* - * Interrupt service routine. This gets called whenever an I2C master interrupt - * occurs. - */ -static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) +static void i2c_dw_process_transfer(struct dw_i2c_dev *dev, unsigned int stat) { - struct dw_i2c_dev *dev = dev_id; - unsigned int stat, enabled; - - regmap_read(dev->map, DW_IC_ENABLE, &enabled); - regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat); - if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY)) - return IRQ_NONE; - if (pm_runtime_suspended(dev->dev) || stat == GENMASK(31, 0)) - return IRQ_NONE; - dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat); - - stat = i2c_dw_read_clear_intrbits(dev); - - if (!(dev->status & STATUS_ACTIVE)) { - /* - * Unexpected interrupt in driver point of view. State - * variables are either unset or stale so acknowledge and - * disable interrupts for suppressing further interrupts if - * interrupt really came from this HW (E.g. firmware has left - * the HW active). - */ - __i2c_dw_write_intr_mask(dev, 0); - return IRQ_HANDLED; - } - if (stat & DW_IC_INTR_TX_ABRT) { dev->cmd_err |= DW_IC_ERR_TX_ABRT; dev->status &= ~STATUS_MASK; @@ -755,10 +670,73 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) __i2c_dw_write_intr_mask(dev, 0); __i2c_dw_write_intr_mask(dev, stat); } +} + +/* + * Interrupt service routine. This gets called whenever an I2C master interrupt + * occurs. + */ +static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) +{ + struct dw_i2c_dev *dev = dev_id; + unsigned int stat, enabled; + + regmap_read(dev->map, DW_IC_ENABLE, &enabled); + regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat); + if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY)) + return IRQ_NONE; + if (pm_runtime_suspended(dev->dev) || stat == GENMASK(31, 0)) + return IRQ_NONE; + dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat); + + stat = i2c_dw_read_clear_intrbits(dev); + + if (!(dev->status & STATUS_ACTIVE)) { + /* + * Unexpected interrupt in driver point of view. State + * variables are either unset or stale so acknowledge and + * disable interrupts for suppressing further interrupts if + * interrupt really came from this HW (E.g. firmware has left + * the HW active). + */ + __i2c_dw_write_intr_mask(dev, 0); + return IRQ_HANDLED; + } + + i2c_dw_process_transfer(dev, stat); return IRQ_HANDLED; } +static int i2c_dw_wait_transfer(struct dw_i2c_dev *dev) +{ + unsigned long timeout = dev->adapter.timeout; + unsigned int stat; + int ret = 0; + + if (!(dev->flags & ACCESS_POLLING)) { + ret = wait_for_completion_timeout(&dev->cmd_complete, + timeout) ? 0 : -ETIMEDOUT; + } else { + timeout += jiffies; + do { + if (try_wait_for_completion(&dev->cmd_complete)) + goto out; + + stat = i2c_dw_read_clear_intrbits(dev); + if (stat) + i2c_dw_process_transfer(dev, stat); + else + /* Try save some power */ + usleep_range(3, 25); + } while (time_before(jiffies, timeout)); + ret = ETIMEDOUT; + } + +out: + return ret; +} + /* * Prepare controller for a transaction and call i2c_dw_xfer_msg. */ @@ -781,9 +759,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) case MODEL_AMD_NAVI_GPU: ret = amd_i2c_dw_xfer_quirk(adap, msgs, num); goto done_nolock; - case MODEL_WANGXUN_SP: - ret = txgbe_i2c_dw_xfer_quirk(adap, msgs, num); - goto done_nolock; default: break; } @@ -811,12 +786,12 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) i2c_dw_xfer_init(dev); /* Wait for tx to complete */ - if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { + ret = i2c_dw_wait_transfer(dev); + if (ret) { dev_err(dev->dev, "controller timed out\n"); /* i2c_dw_init implicitly disables the adapter */ i2c_recover_bus(&dev->adapter); i2c_dw_init_master(dev); - ret = -ETIMEDOUT; goto done; }