All of lore.kernel.org
 help / color / mirror / Atom feed
From: William Zhang <william.zhang@broadcom.com>
To: Linux SPI List <linux-spi@vger.kernel.org>,
	Broadcom Kernel List <bcm-kernel-feedback-list@broadcom.com>
Cc: tomer.yacoby@broadcom.com, kursad.oney@broadcom.com,
	dregan@mail.com, f.fainelli@gmail.com, anand.gore@broadcom.com,
	jonas.gorski@gmail.com, dan.beygelman@broadcom.com,
	joel.peshkin@broadcom.com,
	William Zhang <william.zhang@broadcom.com>,
	Mark Brown <broonie@kernel.org>,
	linux-kernel@vger.kernel.org
Subject: [PATCH v2 07/14] spi: bcm63xx-hsspi: Add polling mode support
Date: Tue, 24 Jan 2023 14:12:10 -0800	[thread overview]
Message-ID: <20230124221218.341511-8-william.zhang@broadcom.com> (raw)
In-Reply-To: <20230124221218.341511-1-william.zhang@broadcom.com>

Polling mode provides better throughput in general by avoiding the
interrupt overhead as the maximum data size one interrupt can handle is
only 512 bytes. So switch to polling mode as the default mode but add
a driver sysfs option wait_mode to allow user manually changing the mode
at run time between interrupt and polling. Also add driver banner
message when the driver is loaded successfully.

When test on a Broadcom BCM47622(ARM A7 dual core) reference board with
WINBOND W25N01GV SPI NAND chip at 100MHz SPI clock using the MTD speed
test suite, it shows about 15% improvement on the write and 30% on
the read:
** Interrupt mode **
  mtd_speedtest: MTD device: 0    count: 16
  mtd_speedtest: MTD device size 134217728, eraseblock size 131072, page
size 2048, count of eraseblocks 1024, pages per eraseblock 64, OOB size
64
  mtd_test: scanning for bad eraseblocks
  mtd_test: scanned 16 eraseblocks, 0 are bad
  mtd_speedtest: testing eraseblock write speed
  mtd_speedtest: eraseblock write speed is 3072 KiB/s
  mtd_speedtest: testing eraseblock read speed
  mtd_speedtest: eraseblock read speed is 6690 KiB/s
  mtd_speedtest: testing page write speed
  mtd_speedtest: page write speed is 3066 KiB/s
  mtd_speedtest: testing page read speed
  mtd_speedtest: page read speed is 6762 KiB/s
  mtd_speedtest: testing 2 page write speed
  mtd_speedtest: 2 page write speed is 3071 KiB/s
  mtd_speedtest: testing 2 page read speed
  mtd_speedtest: 2 page read speed is 6772 KiB/s
** Polling mode **
  mtd_speedtest: MTD device: 0    count: 16
  mtd_speedtest: MTD device size 134217728, eraseblock size 131072, page
size 2048, count of eraseblocks 1024, pages per eraseblock 64, OOB size
64
  mtd_test: scanning for bad eraseblocks
  mtd_test: scanned 16 eraseblocks, 0 are bad
  mtd_speedtest: testing eraseblock write speed
  mtd_speedtest: eraseblock write speed is 3542 KiB/s
  mtd_speedtest: testing eraseblock read speed
  mtd_speedtest: eraseblock read speed is 8825 KiB/s
  mtd_speedtest: testing page write speed
  mtd_speedtest: page write speed is 3563 KiB/s
  mtd_speedtest: testing page read speed
  mtd_speedtest: page read speed is 8787 KiB/s
  mtd_speedtest: testing 2 page write speed
  mtd_speedtest: 2 page write speed is 3572 KiB/s
  mtd_speedtest: testing 2 page read speed
  mtd_speedtest: 2 page read speed is 8806 KiB/s

Signed-off-by: William Zhang <william.zhang@broadcom.com>

---

Changes in v2:
- Make interrupt as required node in the dts
- Use polling mode as default mode
- Add driver sysfs option wait_mode to allow mode change at run time
- Update commit message

 drivers/spi/spi-bcm63xx-hsspi.c | 109 ++++++++++++++++++++++++++++----
 1 file changed, 98 insertions(+), 11 deletions(-)

diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c
index a65a0ec67641..55cbe7deba08 100644
--- a/drivers/spi/spi-bcm63xx-hsspi.c
+++ b/drivers/spi/spi-bcm63xx-hsspi.c
@@ -57,6 +57,7 @@
 #define PINGPONG_CMD_SS_SHIFT			12
 
 #define HSSPI_PINGPONG_STATUS_REG(x)		(0x84 + (x) * 0x40)
+#define HSSPI_PINGPONG_STATUS_SRC_BUSY		BIT(1)
 
 #define HSSPI_PROFILE_CLK_CTRL_REG(x)		(0x100 + (x) * 0x20)
 #define CLK_CTRL_FREQ_CTRL_MASK			0x0000ffff
@@ -96,11 +97,16 @@
 
 #define HSSPI_SPI_MAX_CS			8
 #define HSSPI_BUS_NUM				1 /* 0 is legacy SPI */
+#define HSSPI_POLL_STATUS_TIMEOUT_MS	100
+
+#define HSSPI_WAIT_MODE_POLLING		0
+#define HSSPI_WAIT_MODE_INTR		1
+#define HSSPI_WAIT_MODE_MAX			HSSPI_WAIT_MODE_INTR
 
 struct bcm63xx_hsspi {
 	struct completion done;
 	struct mutex bus_mutex;
-
+	struct mutex msg_mutex;
 	struct platform_device *pdev;
 	struct clk *clk;
 	struct clk *pll_clk;
@@ -109,6 +115,52 @@ struct bcm63xx_hsspi {
 
 	u32 speed_hz;
 	u8 cs_polarity;
+	u32 wait_mode;
+};
+
+static ssize_t wait_mode_show(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct spi_controller *ctrl = dev_get_drvdata(dev);
+	struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+
+	return sprintf(buf, "%d\n", bs->wait_mode);
+}
+
+static ssize_t wait_mode_store(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct spi_controller *ctrl = dev_get_drvdata(dev);
+	struct bcm63xx_hsspi *bs = spi_master_get_devdata(ctrl);
+	u32 val;
+
+	if (kstrtou32(buf, 10, &val))
+		return -EINVAL;
+
+	if (val > HSSPI_WAIT_MODE_MAX) {
+		dev_warn(dev, "invalid wait mode %u\n", val);
+		return -EINVAL;
+	}
+
+	mutex_lock(&bs->msg_mutex);
+	bs->wait_mode = val;
+	/* clear interrupt status to avoid spurious int on next transfer */
+	if (val == HSSPI_WAIT_MODE_INTR)
+		__raw_writel(HSSPI_INT_CLEAR_ALL, bs->regs + HSSPI_INT_STATUS_REG);
+	mutex_unlock(&bs->msg_mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR_RW(wait_mode);
+
+static struct attribute *bcm63xx_hsspi_attrs[] = {
+	&dev_attr_wait_mode.attr,
+	NULL,
+};
+
+static const struct attribute_group bcm63xx_hsspi_group = {
+	.attrs = bcm63xx_hsspi_attrs,
 };
 
 static void bcm63xx_hsspi_set_cs(struct bcm63xx_hsspi *bs, unsigned int cs,
@@ -163,6 +215,8 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
 	int step_size = HSSPI_BUFFER_LEN;
 	const u8 *tx = t->tx_buf;
 	u8 *rx = t->rx_buf;
+	u32 val;
+	unsigned long limit;
 
 	bcm63xx_hsspi_set_clk(bs, spi, t->speed_hz);
 	bcm63xx_hsspi_set_cs(bs, spi->chip_select, true);
@@ -197,8 +251,9 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
 		__raw_writew((u16)cpu_to_be16(opcode | curr_step), bs->fifo);
 
 		/* enable interrupt */
-		__raw_writel(HSSPI_PINGx_CMD_DONE(0),
-			     bs->regs + HSSPI_INT_MASK_REG);
+		if (bs->wait_mode == HSSPI_WAIT_MODE_INTR)
+			__raw_writel(HSSPI_PINGx_CMD_DONE(0),
+				     bs->regs + HSSPI_INT_MASK_REG);
 
 		/* start the transfer */
 		__raw_writel(!chip_select << PINGPONG_CMD_SS_SHIFT |
@@ -206,9 +261,21 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
 			     PINGPONG_COMMAND_START_NOW,
 			     bs->regs + HSSPI_PINGPONG_COMMAND_REG(0));
 
-		if (wait_for_completion_timeout(&bs->done, HZ) == 0) {
-			dev_err(&bs->pdev->dev, "transfer timed out!\n");
-			return -ETIMEDOUT;
+		if (bs->wait_mode == HSSPI_WAIT_MODE_INTR) {
+			if (wait_for_completion_timeout(&bs->done, HZ) == 0)
+				goto err_timeout;
+		} else {
+			/* polling mode checks for status busy bit */
+			limit = jiffies + msecs_to_jiffies(HSSPI_POLL_STATUS_TIMEOUT_MS);
+			while (!time_after(jiffies, limit)) {
+				val = __raw_readl(bs->regs + HSSPI_PINGPONG_STATUS_REG(0));
+				if (val & HSSPI_PINGPONG_STATUS_SRC_BUSY)
+					cpu_relax();
+				else
+					break;
+			}
+			if (val & HSSPI_PINGPONG_STATUS_SRC_BUSY)
+				goto err_timeout;
 		}
 
 		if (rx) {
@@ -220,6 +287,10 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t)
 	}
 
 	return 0;
+
+err_timeout:
+	dev_err(&bs->pdev->dev, "transfer timed out!\n");
+	return -ETIMEDOUT;
 }
 
 static int bcm63xx_hsspi_setup(struct spi_device *spi)
@@ -269,6 +340,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
 	int dummy_cs;
 	u32 reg;
 
+	mutex_lock(&bs->msg_mutex);
 	/* This controller does not support keeping CS active during idle.
 	 * To work around this, we use the following ugly hack:
 	 *
@@ -306,6 +378,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master,
 	__raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG);
 	mutex_unlock(&bs->bus_mutex);
 
+	mutex_unlock(&bs->msg_mutex);
 	msg->status = status;
 	spi_finalize_current_message(master);
 
@@ -398,8 +471,10 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
 	bs->regs = regs;
 	bs->speed_hz = rate;
 	bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0));
+	bs->wait_mode = HSSPI_WAIT_MODE_POLLING;
 
 	mutex_init(&bs->bus_mutex);
+	mutex_init(&bs->msg_mutex);
 	init_completion(&bs->done);
 
 	master->dev.of_node = dev->of_node;
@@ -434,21 +509,32 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
 	__raw_writel(reg | GLOBAL_CTRL_CLK_GATE_SSOFF,
 		     bs->regs + HSSPI_GLOBAL_CTRL_REG);
 
-	ret = devm_request_irq(dev, irq, bcm63xx_hsspi_interrupt, IRQF_SHARED,
-			       pdev->name, bs);
+	if (irq > 0) {
+		ret = devm_request_irq(dev, irq, bcm63xx_hsspi_interrupt, IRQF_SHARED,
+				       pdev->name, bs);
 
-	if (ret)
-		goto out_put_master;
+		if (ret)
+			goto out_put_master;
+	}
 
 	pm_runtime_enable(&pdev->dev);
 
+	if (sysfs_create_group(&pdev->dev.kobj, &bcm63xx_hsspi_group)) {
+		dev_err(&pdev->dev, "couldn't register sysfs group\n");
+		goto out_pm_disable;
+	}
+
 	/* register and we are done */
 	ret = devm_spi_register_master(dev, master);
 	if (ret)
-		goto out_pm_disable;
+		goto out_sysgroup_disable;
+
+	dev_info(dev, "Broadcom 63XX High Speed SPI Controller driver");
 
 	return 0;
 
+out_sysgroup_disable:
+	sysfs_remove_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
 out_pm_disable:
 	pm_runtime_disable(&pdev->dev);
 out_put_master:
@@ -470,6 +556,7 @@ static int bcm63xx_hsspi_remove(struct platform_device *pdev)
 	__raw_writel(0, bs->regs + HSSPI_INT_MASK_REG);
 	clk_disable_unprepare(bs->pll_clk);
 	clk_disable_unprepare(bs->clk);
+	sysfs_remove_group(&pdev->dev.kobj, &bcm63xx_hsspi_group);
 
 	return 0;
 }
-- 
2.37.3


  parent reply	other threads:[~2023-01-24 22:33 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-24 22:12 [PATCH v2 00/14] spi: bcm63xx-hsspi: driver and doc updates William Zhang
2023-01-24 22:12 ` William Zhang
2023-01-24 22:12 ` [PATCH v2 01/14] dt-bindings: spi: Convert bcm63xx-hsspi bindings to json-schema William Zhang
2023-01-25  7:31   ` Krzysztof Kozlowski
2023-01-24 22:12 ` [PATCH v2 02/14] dt-bindings: spi: Add bcmbca-hsspi controller support William Zhang
2023-01-25  7:35   ` Krzysztof Kozlowski
2023-01-25 19:23     ` William Zhang
2023-01-25 20:51       ` Rob Herring
2023-01-25 21:40         ` William Zhang
2023-01-26 13:56           ` Rob Herring
2023-01-26 20:04             ` William Zhang
2023-01-24 22:12 ` [PATCH v2 03/14] ARM: dts: broadcom: bcmbca: Add spi controller node William Zhang
2023-01-24 22:12   ` William Zhang
2023-01-25  7:36   ` Krzysztof Kozlowski
2023-01-25  7:36     ` Krzysztof Kozlowski
2023-01-24 22:12 ` [PATCH v2 04/14] arm64: " William Zhang
2023-01-24 22:12   ` William Zhang
2023-01-24 22:12 ` [PATCH v2 05/14] spi: bcm63xx-hsspi: Add new compatible string support William Zhang
2023-01-24 22:12 ` [PATCH v2 06/14] spi: bcm63xx-hsspi: Endianness fix for ARM based SoC William Zhang
2023-01-24 22:48   ` Florian Fainelli
2023-01-24 22:12 ` William Zhang [this message]
2023-01-24 22:12 ` [PATCH v2 08/14] spi: bcm63xx-hsspi: Handle cs_change correctly William Zhang
2023-01-26 15:12   ` Jonas Gorski
2023-01-26 16:22     ` Kursad Oney
2023-01-26 17:33       ` Jonas Gorski
2023-01-27  3:10         ` William Zhang
2023-01-24 22:12 ` [PATCH v2 09/14] spi: bcm63xx-hsspi: Fix multi-bit mode setting William Zhang
2023-01-24 22:12 ` [PATCH v2 10/14] spi: bcm63xx-hsspi: Add prepend mode support William Zhang
2023-01-26 15:15   ` Jonas Gorski
2023-01-26 15:33     ` Mark Brown
2023-01-27  2:59     ` William Zhang
2023-01-24 22:12 ` [PATCH v2 11/14] spi: spi-mem: Allow controller supporting mem_ops without exec_op William Zhang
2023-01-24 22:12 ` [PATCH v2 12/14] spi: bcm63xx-hsspi: Disable spi mem dual io William Zhang
2023-01-26 15:15   ` Jonas Gorski
2023-01-27  2:04     ` William Zhang
2023-01-24 22:12 ` [PATCH v2 13/14] spi: bcmbca-hsspi: Add driver for newer HSSPI controller William Zhang
2023-01-24 22:12   ` William Zhang
2023-01-26 15:16   ` Jonas Gorski
2023-01-26 15:16     ` Jonas Gorski
2023-01-27  2:17     ` William Zhang
2023-01-27  2:17       ` William Zhang
2023-01-24 22:12 ` [PATCH v2 14/14] MAINTAINERS: Add entry for Broadcom Broadband SoC HS SPI drivers William Zhang
2023-01-24 22:50   ` Florian Fainelli

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230124221218.341511-8-william.zhang@broadcom.com \
    --to=william.zhang@broadcom.com \
    --cc=anand.gore@broadcom.com \
    --cc=bcm-kernel-feedback-list@broadcom.com \
    --cc=broonie@kernel.org \
    --cc=dan.beygelman@broadcom.com \
    --cc=dregan@mail.com \
    --cc=f.fainelli@gmail.com \
    --cc=joel.peshkin@broadcom.com \
    --cc=jonas.gorski@gmail.com \
    --cc=kursad.oney@broadcom.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-spi@vger.kernel.org \
    --cc=tomer.yacoby@broadcom.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.