All of lore.kernel.org
 help / color / mirror / Atom feed
From: Aleksandar Markovic <aleksandar.markovic@rt-rk.com>
To: linux-mips@linux-mips.org, James.Hogan@imgtec.com,
	Paul.Burton@imgtec.com
Cc: Raghu.Gandham@imgtec.com, Leonid.Yegoshin@imgtec.com,
	Douglas.Leung@imgtec.com, Petar.Jovanovic@imgtec.com,
	Miodrag.Dinic@imgtec.com, Goran.Ferenc@imgtec.com
Subject: [PATCH 7/8] tty: goldfish: Use streaming DMA for r/w operations on Ranchu platforms
Date: Mon, 19 Jun 2017 17:50:14 +0200	[thread overview]
Message-ID: <1497887415-13825-8-git-send-email-aleksandar.markovic@rt-rk.com> (raw)
In-Reply-To: <1497887415-13825-1-git-send-email-aleksandar.markovic@rt-rk.com>

From: Miodrag Dinic <miodrag.dinic@imgtec.com>

Implement tty r/w operations using streaming DMA.

Goldfish tty for Ranchu platforms has been modified to use
streaming DMA mappings for read/write operations. This change
eliminates the need for snooping through the TLB in QEMU using
cpu_get_phys_page_debug() which does not guarantee that it will
return the valid va -> pa mapping.

The streaming DMA mapping is implemented using dma_map_single() per
transfer, while dma_unmap_single() is used for unmapping right after
the DMA transfer.

Using DMA API is the proper way for handling r/w transfers and
makes this driver more portable, thus effectively eliminating
the need for virt_to_page() and page_to_phys() conversions.

This change does not affect the old style Goldfish tty behaviour
which is still used by the Goldfish emulator. Version register has
been added and probed to see which platform is running this driver.
Reading from the new GOLDFISH_TTY_VERSION register using the Goldfish
emulator will return 0 and driver will work with virtual addresses.
Whereas if run on Ranchu it returns 1, and thus DMA is used.

Signed-off-by: Miodrag Dinic <miodrag.dinic@imgtec.com>
Signed-off-by: Goran Ferenc <goran.ferenc@imgtec.com>
Signed-off-by: Aleksandar Markovic <aleksandar.markovic@imgtech.com>
---
 drivers/tty/goldfish.c | 119 ++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 108 insertions(+), 11 deletions(-)

diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c
index 996bd47..acd50fa 100644
--- a/drivers/tty/goldfish.c
+++ b/drivers/tty/goldfish.c
@@ -22,6 +22,8 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/goldfish.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
 
 enum {
 	GOLDFISH_TTY_PUT_CHAR       = 0x00,
@@ -32,6 +34,8 @@ enum {
 	GOLDFISH_TTY_DATA_LEN       = 0x14,
 	GOLDFISH_TTY_DATA_PTR_HIGH  = 0x18,
 
+	GOLDFISH_TTY_VERSION		= 0x20,
+
 	GOLDFISH_TTY_CMD_INT_DISABLE    = 0,
 	GOLDFISH_TTY_CMD_INT_ENABLE     = 1,
 	GOLDFISH_TTY_CMD_WRITE_BUFFER   = 2,
@@ -45,6 +49,8 @@ struct goldfish_tty {
 	u32 irq;
 	int opencount;
 	struct console console;
+	u32 version;
+	struct device *dev;
 };
 
 static DEFINE_MUTEX(goldfish_tty_lock);
@@ -53,24 +59,94 @@ static u32 goldfish_tty_line_count = 8;
 static u32 goldfish_tty_current_line_count;
 static struct goldfish_tty *goldfish_ttys;
 
-static void goldfish_tty_do_write(int line, const char *buf, unsigned count)
+static inline void do_rw_io(struct goldfish_tty *qtty,
+				unsigned long address,
+				unsigned int count,
+				int is_write)
 {
 	unsigned long irq_flags;
-	struct goldfish_tty *qtty = &goldfish_ttys[line];
 	void __iomem *base = qtty->base;
+
 	spin_lock_irqsave(&qtty->lock, irq_flags);
-	gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR,
+	gf_write_ptr((void *)address, base + GOLDFISH_TTY_DATA_PTR,
 				base + GOLDFISH_TTY_DATA_PTR_HIGH);
 	writel(count, base + GOLDFISH_TTY_DATA_LEN);
-	writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD);
+
+	if (is_write)
+		writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD);
+	else
+		writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD);
+
 	spin_unlock_irqrestore(&qtty->lock, irq_flags);
 }
 
+static inline void goldfish_tty_rw(struct goldfish_tty *qtty,
+				unsigned long addr,
+				unsigned int count,
+				int is_write)
+{
+	dma_addr_t dma_handle;
+	enum dma_data_direction dma_dir;
+
+	dma_dir = (is_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+	if (qtty->version) {
+		/*
+		 * Goldfish TTY for Ranchu platform uses
+		 * physical addresses and DMA for read/write operations
+		 */
+		unsigned long addr_end = addr + count;
+
+		while (addr < addr_end) {
+			unsigned long pg_end = (addr & PAGE_MASK) + PAGE_SIZE;
+			unsigned long next =
+					pg_end < addr_end ? pg_end : addr_end;
+			unsigned long avail = next - addr;
+
+			/*
+			 * Map the buffer's virtual address to the DMA address
+			 * so the buffer can be accessed by the device.
+			 */
+			dma_handle = dma_map_single(qtty->dev,
+						(void *)addr, avail, dma_dir);
+
+			if (dma_mapping_error(qtty->dev, dma_handle)) {
+				dev_err(qtty->dev, "tty: DMA mapping error.\n");
+				return;
+			}
+			do_rw_io(qtty, dma_handle, avail, is_write);
+
+			/*
+			 * Unmap the previously mapped region after
+			 * the completion of the read/write operation.
+			 */
+			dma_unmap_single(qtty->dev, dma_handle, avail, dma_dir);
+
+			addr += avail;
+		}
+	} else {
+		/*
+		 * Old style Goldfish TTY used on the Goldfish platform
+		 * uses virtual addresses.
+		 */
+		do_rw_io(qtty, addr, count, is_write);
+	}
+
+}
+
+static void goldfish_tty_do_write(int line, const char *buf,
+				unsigned int count)
+{
+	struct goldfish_tty *qtty = &goldfish_ttys[line];
+	unsigned long address = (unsigned long)(void *)buf;
+
+	goldfish_tty_rw(qtty, address, count, 1);
+}
+
 static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
 {
 	struct goldfish_tty *qtty = dev_id;
 	void __iomem *base = qtty->base;
-	unsigned long irq_flags;
+	unsigned long address;
 	unsigned char *buf;
 	u32 count;
 
@@ -79,12 +155,10 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id)
 		return IRQ_NONE;
 
 	count = tty_prepare_flip_string(&qtty->port, &buf, count);
-	spin_lock_irqsave(&qtty->lock, irq_flags);
-	gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR,
-				base + GOLDFISH_TTY_DATA_PTR_HIGH);
-	writel(count, base + GOLDFISH_TTY_DATA_LEN);
-	writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD);
-	spin_unlock_irqrestore(&qtty->lock, irq_flags);
+
+	address = (unsigned long)(void *)buf;
+	goldfish_tty_rw(qtty, address, count, 0);
+
 	tty_schedule_flip(&qtty->port);
 	return IRQ_HANDLED;
 }
@@ -271,6 +345,29 @@ static int goldfish_tty_probe(struct platform_device *pdev)
 	qtty->port.ops = &goldfish_port_ops;
 	qtty->base = base;
 	qtty->irq = irq;
+	qtty->dev = &pdev->dev;
+
+	/* Goldfish TTY device used by the Goldfish emulator
+	 * should identify itself with 0, forcing the driver
+	 * to use virtual addresses. Goldfish TTY device
+	 * on Ranchu emulator (qemu2) returns 1 here and
+	 * driver will use physical addresses.
+	 */
+	qtty->version = readl(base + GOLDFISH_TTY_VERSION);
+
+	/* Goldfish TTY device on Ranchu emulator (qemu2)
+	 * will use DMA for read/write IO operations.
+	 */
+	if (qtty->version > 0) {
+		/* Initialize dma_mask to 32-bits.
+		 */
+		if (!pdev->dev.dma_mask)
+			pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+		if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
+			dev_err(&pdev->dev, "No suitable DMA available.\n");
+			goto err_create_driver_failed;
+		}
+	}
 
 	writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD);
 
-- 
2.7.4

  parent reply	other threads:[~2017-06-19 15:58 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-19 15:50 [PATCH 0/8] MIPS: Miscellaneous fixes related to Android Mips emulator Aleksandar Markovic
2017-06-19 15:50 ` [PATCH 1/8] MIPS: cmdline: Add support for 'memmap' parameter Aleksandar Markovic
2017-06-19 15:50 ` [PATCH 2/8] MIPS: build: Fix "-modd-spreg" switch usage when compiling for mips32r6 Aleksandar Markovic
2017-06-19 15:50 ` [PATCH 3/8] MIPS: R6: Fix PREF instruction usage by memcpy for MIPS R6 Aleksandar Markovic
2017-06-20  8:04   ` Matt Redfearn
2017-06-20  8:04     ` Matt Redfearn
2017-06-28  0:58     ` Ralf Baechle
2017-06-28  1:35       ` Maciej W. Rozycki
2017-06-28  1:35         ` Maciej W. Rozycki
     [not found]         ` <9915e476-70fe-4281-a1e4-85ca2e8683b3@imgtec.com>
2017-06-28  2:36           ` Maciej W. Rozycki
2017-06-28  8:34             ` Ralf Baechle
2017-06-28 11:23               ` Maciej W. Rozycki
2017-06-19 15:50 ` [PATCH 4/8] MIPS: unaligned: Add DSP lwx & lhx missaligned access support Aleksandar Markovic
2017-06-19 15:50 ` [PATCH 5/8] MIPS: math-emu: Handle zero accumulator case in MADDF and MSUBF separately Aleksandar Markovic
2017-06-19 15:50 ` [PATCH 6/8] input: goldfish: Fix multitouch event handling Aleksandar Markovic
2017-06-19 15:50 ` Aleksandar Markovic [this message]
2017-06-19 15:50 ` [PATCH 8/8] tty: goldfish: Implement support for kernel 'earlycon' parameter Aleksandar Markovic

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=1497887415-13825-8-git-send-email-aleksandar.markovic@rt-rk.com \
    --to=aleksandar.markovic@rt-rk.com \
    --cc=Douglas.Leung@imgtec.com \
    --cc=Goran.Ferenc@imgtec.com \
    --cc=James.Hogan@imgtec.com \
    --cc=Leonid.Yegoshin@imgtec.com \
    --cc=Miodrag.Dinic@imgtec.com \
    --cc=Paul.Burton@imgtec.com \
    --cc=Petar.Jovanovic@imgtec.com \
    --cc=Raghu.Gandham@imgtec.com \
    --cc=linux-mips@linux-mips.org \
    /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.