* Re: PL2303 Driver Issue
From: Greg KH @ 2012-10-07 14:47 UTC (permalink / raw)
To: Reddy Kaveri, Praveen Kumar; +Cc: linux-serial@vger.kernel.org
In-Reply-To: <523E9909A6DFCF469669581BEB8DA7AA56928B25@G2W2441.americas.hpqcorp.net>
On Sat, Oct 06, 2012 at 06:33:19PM +0000, Reddy Kaveri, Praveen Kumar wrote:
> Hi,
>
> I am using Telxon PTC-710 device in linux environment and I am using
> RS232 Serial to USB converter. When I connect the device to USB port
> it is detecting and showing in the system log as "attached to
> ttyUSB0". I have written a java program to display all the available
> ports. But this program is displaying only ttyS0 &ttyS1. I have tried
> to set all permissions to the user as well as to port. Please help me
> if I am missing any configuration related to this driver.
You are going to have to modify your userspace program to know to look
for the ttyUSBX devices as well. There's nothing the kernel can do
about this.
As you wrote the program, how are you getting the list of serial devices
in the system?
greg k-h
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [tty:tty-next 9/39] drivers/staging/dgrp/dgrp_tty.c:3177 dgrp_tty_init() error: potential null dereference 'nd->nd_serial_ttdriver'.
From: Fengguang Wu @ 2012-10-07 12:35 UTC (permalink / raw)
To: Bill Pemberton; +Cc: kernel-janitors, Greg Kroah-Hartman, linux-serial
Hi Bill,
FYI, there are new smatch warnings show up in
tree: git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-next
head: 0c57dfcc6c1d037243c2f8fbf62eab3633326ec0
commit: 7b6d45c211a401a9bdeebfa96f8a4c811bd3eeaf [9/39] staging: dgrp: add dgrp to the build
It seems that the dgrp_dpa_ops.c ones are false warnings, while the
'potential null deference' ones are worth looking at.
+ drivers/staging/dgrp/dgrp_dpa_ops.c:377 dgrp_dpa_ioctl() warn: 'vpd' puts 516 bytes on stack
--
+ drivers/staging/dgrp/dgrp_net_ops.c:277 dgrp_input() error: we previously assumed 'ld' could be null (see line 238)
+ drivers/staging/dgrp/dgrp_net_ops.c:3159 dgrp_receive() error: strncpy() 'nd->nd_ps_desc' too small (101 vs 988)
+ drivers/staging/dgrp/dgrp_net_ops.c:3160 dgrp_receive() error: buffer overflow 'nd->nd_ps_desc' 101 <= 988
--
+ drivers/staging/dgrp/dgrp_specproc.c:273 register_proc_table() error: we previously assumed 'table->child' could be null (see line 263)
--
+ drivers/staging/dgrp/dgrp_tty.c:2341 dgrp_set_custom_speed() info: ignoring unreachable code.
+ drivers/staging/dgrp/dgrp_tty.c:3177 dgrp_tty_init() error: potential null dereference 'nd->nd_serial_ttdriver'. (alloc_tty_driver returns null)
+ drivers/staging/dgrp/dgrp_tty.c:3236 dgrp_tty_init() error: potential null dereference 'nd->nd_callout_ttdriver'. (alloc_tty_driver returns null)
+ drivers/staging/dgrp/dgrp_tty.c:3273 dgrp_tty_init() error: potential null dereference 'nd->nd_xprint_ttdriver'. (alloc_tty_driver returns null)
---
0-DAY kernel build testing backend Open Source Technology Center
Fengguang Wu, Yuanhan Liu Intel Corporation
^ permalink raw reply
* [PATCH 3/6] tty: atmel_serial: switch pm ops
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-10-07 7:27 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Nicolas Ferre, Jean-Christophe PLAGNIOL-VILLARD, linux-serial,
linux-pm
In-Reply-To: <1349594840-11374-1-git-send-email-plagnioj@jcrosoft.com>
so we can detect when we enter in slow_clock mode and drop
at91_suspend_entering_slow_clock
Cc: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Cc: linux-pm@vger.kernel.org
Cc: linux-serial@vger.kernel.org
---
drivers/tty/serial/atmel_serial.c | 52 +++++++++++++++++++------------------
1 file changed, 27 insertions(+), 25 deletions(-)
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 3d7e1ee..7a51a0c 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -1720,20 +1720,10 @@ static struct uart_driver atmel_uart = {
};
#ifdef CONFIG_PM
-static bool atmel_serial_clk_will_stop(void)
+static int atmel_serial_suspend(struct device *dev, int slow_clock)
{
-#ifdef CONFIG_ARCH_AT91
- return at91_suspend_entering_slow_clock();
-#else
- return false;
-#endif
-}
-
-static int atmel_serial_suspend(struct platform_device *pdev,
- pm_message_t state)
-{
- struct uart_port *port = platform_get_drvdata(pdev);
- struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct atmel_uart_port *atmel_port = dev_get_drvdata(dev);
+ struct uart_port *port = &atmel_port->uart;
if (atmel_is_console_port(port) && console_suspend_enabled) {
/* Drain the TX shifter */
@@ -1742,30 +1732,43 @@ static int atmel_serial_suspend(struct platform_device *pdev,
}
/* we can not wake up if we're running on slow clock */
- atmel_port->may_wakeup = device_may_wakeup(&pdev->dev);
- if (atmel_serial_clk_will_stop())
- device_set_wakeup_enable(&pdev->dev, 0);
+ atmel_port->may_wakeup = device_may_wakeup(dev);
+ if (slow_clock)
+ device_set_wakeup_enable(dev, 0);
uart_suspend_port(&atmel_uart, port);
return 0;
}
-static int atmel_serial_resume(struct platform_device *pdev)
+static int atmel_serial_suspend_standby(struct device *dev)
{
- struct uart_port *port = platform_get_drvdata(pdev);
- struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ return atmel_serial_suspend(dev, 0);
+}
+
+static int atmel_serial_suspend_mem(struct device *dev)
+{
+ return atmel_serial_suspend(dev, 1);
+}
+
+static int atmel_serial_resume(struct device *dev)
+{
+ struct atmel_uart_port *atmel_port = dev_get_drvdata(dev);
+ struct uart_port *port = &atmel_port->uart;
uart_resume_port(&atmel_uart, port);
- device_set_wakeup_enable(&pdev->dev, atmel_port->may_wakeup);
+ device_set_wakeup_enable(dev, atmel_port->may_wakeup);
return 0;
}
-#else
-#define atmel_serial_suspend NULL
-#define atmel_serial_resume NULL
#endif
+static struct dev_pm_ops atmel_serial_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(atmel_serial_suspend_standby, atmel_serial_resume)
+ SET_SYSTEM_SLEEP_STANDBY_MEM_PM_OPS(atmel_serial_suspend_standby,
+ atmel_serial_suspend_mem)
+};
+
static int __devinit atmel_serial_probe(struct platform_device *pdev)
{
struct atmel_uart_port *port;
@@ -1877,11 +1880,10 @@ static int __devexit atmel_serial_remove(struct platform_device *pdev)
static struct platform_driver atmel_serial_driver = {
.probe = atmel_serial_probe,
.remove = __devexit_p(atmel_serial_remove),
- .suspend = atmel_serial_suspend,
- .resume = atmel_serial_resume,
.driver = {
.name = "atmel_usart",
.owner = THIS_MODULE,
+ .pm = &atmel_serial_pm_ops,
.of_match_table = of_match_ptr(atmel_serial_dt_ids),
},
};
--
1.7.10.4
^ permalink raw reply related
* RE: PL2303 Driver Issue
From: Reddy Kaveri, Praveen Kumar @ 2012-10-06 18:33 UTC (permalink / raw)
To: linux-serial@vger.kernel.org
Hi,
I am using Telxon PTC-710 device in linux environment and I am using RS232 Serial to USB converter. When I connect the device to USB port it is detecting and showing in the system log as "attached to ttyUSB0". I have written a java program to display all the available ports. But this program is displaying only ttyS0 &ttyS1. I have tried to set all permissions to the user as well as to port. Please help me if I am missing any configuration related to this driver.
I look forward to hearing from you.
Thanks In advance
Regards,
Praveen Kumar Reddy K
Hewlett-Packard Company
#101, 1035 64 Ave SE ,Calgary, AB, T2H 2J7, CANADA
+1 403 692 7914 / Tel
+1 403 619 8242 / Mobile
praveen-kumar.reddy-kaveri@hp.com / Email
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC 20/24] SERIAL: core: add xmit buffer allocation callbacks
From: Russell King - ARM Linux @ 2012-10-06 16:51 UTC (permalink / raw)
To: Alan Cox
Cc: Tony Lindgren, Alan Cox, Greg Kroah-Hartman, linux-arm-kernel,
linux-omap, linux-serial
In-Reply-To: <20121006164956.2956375c@pyramind.ukuu.org.uk>
On Sat, Oct 06, 2012 at 04:49:56PM +0100, Alan Cox wrote:
> On Sat, 06 Oct 2012 13:45:47 +0100
> Russell King <rmk+kernel@arm.linux.org.uk> wrote:
>
> > This allows drivers (such as OMAP serial) to allocate and free their
> > transmit buffers in a sane manner, rather than working around the
> > buffer allocation provided by serial_core.
>
> I think this just illustrates how broken the serial_core layering is in
> that drivers can't treat it as a library but get constrained by it.
>
> Fine for now and actually probably a useful hook to begin removing the
> circ buffers for the kernel generic kfifo and other work that needs doing
> eventually.
Yes, I was thinking about turning the 'default' buffer allocation into
a library call which drivers would set, but I felt that's just asking
for a big patch and problems with new drivers appearing.
We could transition it by providing a default buffer allocation call,
converting all the drivers, and then making that call mandatory. That
probably would then give us a better path to convert to kfifo.
The view that serial_core should be a library is one that Ted mentioned
when I created serial_core originally - I disagreed at the time, and
I still believe it would've ended up being much more complex - and
hairy - to go that route at that time. Maybe as things have moved
forward in the tty layer that's changed, but I've been out of tty stuff
for too long to properly comment.
^ permalink raw reply
* Re: [RFC 00/24] OMAP serial driver flow control fixes, and preparation for DMA engine conversion
From: Alan Cox @ 2012-10-06 15:50 UTC (permalink / raw)
To: Russell King - ARM Linux
Cc: Alan Cox, Greg Kroah-Hartman, linux-arm-kernel, linux-omap,
linux-serial, Tony Lindgren
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
On Sat, 6 Oct 2012 13:38:03 +0100
Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:
> Hi,
>
> This series of patches fixes multiple flow control issues with the OMAP
> serial driver, and prepares the driver for DMA engine conversion. We
> require hardware assisted flow control to work properly for DMA support
> otherwise we have no way to properly pause the transmitter.
All the generic parts
Acked-by: Alan Cox <alan@linux.intel.com>
^ permalink raw reply
* Re: [RFC 20/24] SERIAL: core: add xmit buffer allocation callbacks
From: Alan Cox @ 2012-10-06 15:49 UTC (permalink / raw)
To: Russell King
Cc: Tony Lindgren, Alan Cox, Greg Kroah-Hartman, linux-arm-kernel,
linux-omap, linux-serial
In-Reply-To: <E1TKTlL-0002ni-MB@rmk-PC.arm.linux.org.uk>
On Sat, 06 Oct 2012 13:45:47 +0100
Russell King <rmk+kernel@arm.linux.org.uk> wrote:
> This allows drivers (such as OMAP serial) to allocate and free their
> transmit buffers in a sane manner, rather than working around the
> buffer allocation provided by serial_core.
I think this just illustrates how broken the serial_core layering is in
that drivers can't treat it as a library but get constrained by it.
Fine for now and actually probably a useful hook to begin removing the
circ buffers for the kernel generic kfifo and other work that needs doing
eventually.
Alan
^ permalink raw reply
* Re: [RFC 00/24] OMAP serial driver flow control fixes, and preparation for DMA engine conversion
From: Russell King - ARM Linux @ 2012-10-06 15:35 UTC (permalink / raw)
To: Alan Cox, Greg Kroah-Hartman, linux-arm-kernel, linux-omap,
linux-serial, Tony Lindgren
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
Another issue:
serial_omap_set_termios()
{
...
/* FIFOs and DMA Settings */
/* FCR can be changed only when the
* baud clock is not running
* DLL_REG and DLH_REG set to 0.
*/
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_out(up, UART_DLL, 0);
serial_out(up, UART_DLM, 0);
serial_out(up, UART_LCR, 0);
...
serial_out(up, UART_FCR, up->fcr);
...
}
serial_omap_restore_context()
{
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); /* Config B mode */
serial_out(up, UART_DLL, up->dll);
serial_out(up, UART_DLM, up->dlh);
serial_out(up, UART_LCR, 0x0); /* Operational mode */
serial_out(up, UART_IER, up->ier);
serial_out(up, UART_FCR, up->fcr);
}
Either the comment is wrong, or the code in serial_omap_restore_context()
is wrong; they can't both be right. Please can someone let me know which
is the right version so we can fix that inconsistency.
Thanks.
^ permalink raw reply
* Re: [RFC 00/24] OMAP serial driver flow control fixes, and preparation for DMA engine conversion
From: Russell King - ARM Linux @ 2012-10-06 14:39 UTC (permalink / raw)
To: Alan Cox, Greg Kroah-Hartman, linux-arm-kernel, linux-omap,
linux-serial, Tony Lindgren
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
Another potential bug - in serial_omap_set_termios() there is this:
if (up->use_dma) {
serial_out(up, UART_TI752_TLR, 0);
up->scr |= UART_FCR_TRIGGER_4;
} else {
/* Set receive FIFO threshold to 1 byte */
up->fcr &= ~OMAP_UART_FCR_RX_FIFO_TRIG_MASK;
up->fcr |= (0x1 << OMAP_UART_FCR_RX_FIFO_TRIG_SHIFT);
}
Is that:
up->scr |= UART_FCR_TRIGGER_4;
line really correct? It looks wrong to be using a FCR register mask with
something that ends up in the OMAP SCR register...
I'm beginning to wonder how many of the "workarounds" which have been
applied to this driver, particularly those to do with FIFO triggers and
idle stuff are actually down to the horribly broken and buggy set_termios
code. I'm coming to the conclusion that all those workarounds should be
removed, and we start again from a clean slate with a properly written
driver which observes the register access rules - thereby ensuring that
the correct values get written to the registers that we expect them to.
^ permalink raw reply
* Re: [RFC 00/24] OMAP serial driver flow control fixes, and preparation for DMA engine conversion
From: Russell King - ARM Linux @ 2012-10-06 14:23 UTC (permalink / raw)
To: Alan Cox, Greg Kroah-Hartman, linux-arm-kernel, linux-omap,
linux-serial, Tony Lindgren
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
On Sat, Oct 06, 2012 at 01:38:03PM +0100, Russell King - ARM Linux wrote:
> Hi,
>
> This series of patches fixes multiple flow control issues with the OMAP
> serial driver, and prepares the driver for DMA engine conversion. We
> require hardware assisted flow control to work properly for DMA support
> otherwise we have no way to properly pause the transmitter.
>
> This is generated against v3.6, and has been developed mainly by testing
> on the OMAP4430 SDP platform.
>
> Flow control seems to be really broken in the OMAP serial driver as things
> stand today. It just about works with software flow control because the
> generic serial core layer is inserting those characters, but only when the
> legacy DMA support is not being used. Otherwise, flow control is
> completely non-functional.
>
> Issues identified in the OMAP serial driver are:
> - set_mctrl() can only assert modem control lines, once asserted it
> is not possible to deassert them.
> - IXOFF controls sending of XON/XOFF characters, not the reception of
> these sequences.
> - IXON controls the recognition of XON/XOFF characters, not the transmission
> of the same.
> - Wrong bitmasks for hardware assisted software flow control. Bit 2
> in EFR enables sending of XON2/XOFF2 which are never set.
> - No point comparing received characters against XOFF2 ('special character
> detect') as XOFF2 is not set.
> - Fix multiple places where bits 6 and 5 of MCR are attempted to be
> altered, but because EFR ECB is unset, these bits remain unaffected.
> This effectively prevents us accessing the right XON/XOFF/TCR/TLR
> registers.
> - Remove unnecessary read-backs of EFR/MCR/LCR registers - these registers
> don't change beneath us, they are configuration registers which hold their
> values. Not only does this simplify the code, but it makes it more
> readable, and more importantly ensures that we work from a consistent
> state where ->efr never has ECB set, and ->mcr never has the TCRTLR
> bit set.
> - Fix disablement of hardware flow control and IXANY modes; once enabled
> these could never be disabled because nothing in the code ever clears
> these configuration bits.
>
> Once that lot is fixed, these patches expand serial_core to permit hardware
> assisted flow control by:
> - adding throttle/unthrottle callbacks into low level serial drivers,
> which allow them to take whatever action is necessary with hardware
> assisted flow control to throttle the remote end. In the case of
> OMAP serial, this means disabling the RX interrupts so that the FIFO
> fills to the watermark.
>
> We then have a number of cleanups to the OMAP serial code to make the
> set_termios() function clearer and less prone to the kinds of mistakes
> identified above. This results in a great simplification of the flow
> control configuration code.
>
> The OMAP serial driver hacks around with the transmit buffer allocation;
> lets clean that up so that drivers can cleanly allocate their transmitter
> buffer using coherent memory if that's what they desire.
>
> Finally, the last few patches clean up the plat/omap-serial.h header file,
> moving most of its contents into the OMAP serial driver itself. Most of
> this is private to the OMAP serial driver and should never have been
> shared with anything else.
>
> I have omitted to include the conversion of the transmit paths to DMA
> engine. Even with all the above fixed, it has issues when DMA transmit
> is in progress, and a program issues a TCSETS call (as `less' does after
> it has written its prompt.) At the moment, this causes lots of junk to
> be emitted from the serial port when issuing `dmesg | less' which sometimes
> brings the port to a complete halt.
>
> As the OMAP DMA hardware does not have a clean pause when performing a
> MEM->DEV transfer (it discards its FIFO) I do not see a solution to this,
> which probably means that we can _not_ ever support transmit DMA on OMAP
> platforms.
>
> This means the xmit buffer allocation patches are not that useful unless
> a solution to that can be found.
>
> Now, the remaining question is, how much of this patch set do we think
> about merging, and when. Given that flow control in this driver has been
> broken for a very long time, and no one has apparantly noticed, I don't
> think there's any urgency to this, so given its size, my preference would
> be to queue it up for the next merge window. The thing that would worry
> me about applying some of the initial patches is that they may change
> the behaviour today and make any problems here more visible.
I'll add another point to this: serial_omap_restore_context() makes no
attempt to restore neither the protected bits in the MCR register nor
the contents of the TCR and TLR registers. So, hardware assisted flow
control probably won't work at all well after a context loss event.
When I work out how to test this, I'll see about cooking up yet another
fix to this driver.
^ permalink raw reply
* [RFC 24/24] SERIAL: omap: remove OMAP_UART_SYSC_RESET and OMAP_UART_FIFO_CLR
From: Russell King @ 2012-10-06 12:47 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
OMAP_UART_SYSC_RESET and OMAP_UART_FIFO_CLR are unused, remove them.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
arch/arm/plat-omap/include/plat/omap-serial.h | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index bad00f1..da2e51f 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -32,9 +32,6 @@
*/
#define OMAP_SERIAL_NAME "ttyO"
-#define OMAP_UART_SYSC_RESET 0X07
-#define OMAP_UART_FIFO_CLR 0X06
-
struct omap_uart_port_info {
bool dma_enabled; /* To specify DMA Mode */
unsigned int uartclk; /* UART clock rate */
--
1.7.4.4
^ permalink raw reply related
* [RFC 23/24] SERIAL: omap: move driver private definitions and structures to driver
From: Russell King @ 2012-10-06 12:46 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
struct uart_omap_port and struct uart_omap_dma, and associated
definitions are private to the driver, so there's no point them sitting
in an include file under arch/arm. Move them into the driver itself.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
arch/arm/plat-omap/include/plat/omap-serial.h | 87 ------------------------
drivers/tty/serial/omap-serial.c | 88 +++++++++++++++++++++++++
2 files changed, 88 insertions(+), 87 deletions(-)
diff --git a/arch/arm/plat-omap/include/plat/omap-serial.h b/arch/arm/plat-omap/include/plat/omap-serial.h
index 6403441..bad00f1 100644
--- a/arch/arm/plat-omap/include/plat/omap-serial.h
+++ b/arch/arm/plat-omap/include/plat/omap-serial.h
@@ -32,35 +32,9 @@
*/
#define OMAP_SERIAL_NAME "ttyO"
-#define OMAP_MODE13X_SPEED 230400
-
-#define OMAP_UART_SCR_TX_EMPTY 0x08
-
-/* WER = 0x7F
- * Enable module level wakeup in WER reg
- */
-#define OMAP_UART_WER_MOD_WKUP 0X7F
-
-/* Enable XON/XOFF flow control on output */
-#define OMAP_UART_SW_TX 0x08
-
-/* Enable XON/XOFF flow control on input */
-#define OMAP_UART_SW_RX 0x02
-
#define OMAP_UART_SYSC_RESET 0X07
-#define OMAP_UART_TCR_TRIG 0X0F
-#define OMAP_UART_SW_CLR 0XF0
#define OMAP_UART_FIFO_CLR 0X06
-#define OMAP_UART_DMA_CH_FREE -1
-
-#define OMAP_MAX_HSUART_PORTS 4
-
-#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
-
-#define UART_ERRATA_i202_MDR1_ACCESS BIT(0)
-#define UART_ERRATA_i291_DMA_FORCEIDLE BIT(1)
-
struct omap_uart_port_info {
bool dma_enabled; /* To specify DMA Mode */
unsigned int uartclk; /* UART clock rate */
@@ -76,65 +50,4 @@ struct omap_uart_port_info {
void (*enable_wakeup)(struct platform_device *, bool);
};
-struct uart_omap_dma {
- u8 uart_dma_tx;
- u8 uart_dma_rx;
- int rx_dma_channel;
- int tx_dma_channel;
- dma_addr_t rx_buf_dma_phys;
- dma_addr_t tx_buf_dma_phys;
- unsigned int uart_base;
- /*
- * Buffer for rx dma.It is not required for tx because the buffer
- * comes from port structure.
- */
- unsigned char *rx_buf;
- unsigned int prev_rx_dma_pos;
- int tx_buf_size;
- int tx_dma_used;
- int rx_dma_used;
- spinlock_t tx_lock;
- spinlock_t rx_lock;
- /* timer to poll activity on rx dma */
- struct timer_list rx_timer;
- unsigned int rx_buf_size;
- unsigned int rx_poll_rate;
- unsigned int rx_timeout;
-};
-
-struct uart_omap_port {
- struct uart_port port;
- struct uart_omap_dma uart_dma;
- struct platform_device *pdev;
-
- unsigned char ier;
- unsigned char lcr;
- unsigned char mcr;
- unsigned char fcr;
- unsigned char efr;
- unsigned char dll;
- unsigned char dlh;
- unsigned char mdr1;
- unsigned char scr;
-
- int use_dma;
- /*
- * Some bits in registers are cleared on a read, so they must
- * be saved whenever the register is read but the bits will not
- * be immediately processed.
- */
- unsigned int lsr_break_flag;
- unsigned char msr_saved_flags;
- char name[20];
- unsigned long port_activity;
- u32 context_loss_cnt;
- u32 errata;
- u8 wakeups_enabled;
-
- struct pm_qos_request pm_qos_request;
- u32 latency;
- u32 calc_latency;
- struct work_struct qos_work;
-};
-
#endif /* __OMAP_SERIAL_H__ */
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index a5482da..fad157c 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -44,6 +44,8 @@
#include <plat/dmtimer.h>
#include <plat/omap-serial.h>
+#define OMAP_MAX_HSUART_PORTS 4
+
#define UART_BUILD_REVISION(x, y) (((x) << 8) | (y))
#define OMAP_UART_REV_42 0x0402
@@ -51,6 +53,9 @@
#define OMAP_UART_REV_52 0x0502
#define OMAP_UART_REV_63 0x0603
+#define UART_ERRATA_i202_MDR1_ACCESS BIT(0)
+#define UART_ERRATA_i291_DMA_FORCEIDLE BIT(1)
+
#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
/* SCR register bitmasks */
@@ -71,6 +76,89 @@
#define OMAP_UART_MVR_MAJ_SHIFT 8
#define OMAP_UART_MVR_MIN_MASK 0x3f
+#define OMAP_UART_DMA_CH_FREE -1
+
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+#define OMAP_MODE13X_SPEED 230400
+
+#define OMAP_UART_SCR_TX_EMPTY 0x08
+
+/* WER = 0x7F
+ * Enable module level wakeup in WER reg
+ */
+#define OMAP_UART_WER_MOD_WKUP 0X7F
+
+/* Enable XON/XOFF flow control on output */
+#define OMAP_UART_SW_TX 0x08
+
+/* Enable XON/XOFF flow control on input */
+#define OMAP_UART_SW_RX 0x02
+
+#define OMAP_UART_SW_CLR 0xF0
+
+#define OMAP_UART_TCR_TRIG 0x0F
+
+struct uart_omap_dma {
+ u8 uart_dma_tx;
+ u8 uart_dma_rx;
+ int rx_dma_channel;
+ int tx_dma_channel;
+ dma_addr_t rx_buf_dma_phys;
+ dma_addr_t tx_buf_dma_phys;
+ unsigned int uart_base;
+ /*
+ * Buffer for rx dma.It is not required for tx because the buffer
+ * comes from port structure.
+ */
+ unsigned char *rx_buf;
+ unsigned int prev_rx_dma_pos;
+ int tx_buf_size;
+ int tx_dma_used;
+ int rx_dma_used;
+ spinlock_t tx_lock;
+ spinlock_t rx_lock;
+ /* timer to poll activity on rx dma */
+ struct timer_list rx_timer;
+ unsigned int rx_buf_size;
+ unsigned int rx_poll_rate;
+ unsigned int rx_timeout;
+};
+
+struct uart_omap_port {
+ struct uart_port port;
+ struct uart_omap_dma uart_dma;
+ struct platform_device *pdev;
+
+ unsigned char ier;
+ unsigned char lcr;
+ unsigned char mcr;
+ unsigned char fcr;
+ unsigned char efr;
+ unsigned char dll;
+ unsigned char dlh;
+ unsigned char mdr1;
+ unsigned char scr;
+
+ int use_dma;
+ /*
+ * Some bits in registers are cleared on a read, so they must
+ * be saved whenever the register is read but the bits will not
+ * be immediately processed.
+ */
+ unsigned int lsr_break_flag;
+ unsigned char msr_saved_flags;
+ char name[20];
+ unsigned long port_activity;
+ u32 context_loss_cnt;
+ u32 errata;
+ u8 wakeups_enabled;
+
+ struct pm_qos_request pm_qos_request;
+ u32 latency;
+ u32 calc_latency;
+ struct work_struct qos_work;
+};
+
static struct uart_omap_port *serial_omap_port(struct uart_port *port)
{
return container_of(port, struct uart_omap_port, port);
--
1.7.4.4
^ permalink raw reply related
* [RFC 22/24] SERIAL: omap: typesafe conversion from uart_port to uart_omap_port
From: Russell King @ 2012-10-06 12:46 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/omap-serial.c | 49 +++++++++++++++++++++-----------------
1 files changed, 27 insertions(+), 22 deletions(-)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 6054fc8..a5482da 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -71,6 +71,11 @@
#define OMAP_UART_MVR_MAJ_SHIFT 8
#define OMAP_UART_MVR_MIN_MASK 0x3f
+static struct uart_omap_port *serial_omap_port(struct uart_port *port)
+{
+ return container_of(port, struct uart_omap_port, port);
+}
+
static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
/* Forward declaration of functions */
@@ -141,7 +146,7 @@ static void serial_omap_stop_rxdma(struct uart_omap_port *up)
static void serial_omap_enable_ms(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
dev_dbg(up->port.dev, "serial_omap_enable_ms+%d\n", up->port.line);
@@ -153,7 +158,7 @@ static void serial_omap_enable_ms(struct uart_port *port)
static void serial_omap_stop_tx(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
struct omap_uart_port_info *pdata = up->pdev->dev.platform_data;
if (up->use_dma &&
@@ -186,7 +191,7 @@ static void serial_omap_stop_tx(struct uart_port *port)
static void serial_omap_stop_rx(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
pm_runtime_get_sync(&up->pdev->dev);
if (up->use_dma)
@@ -307,7 +312,7 @@ static inline void serial_omap_enable_ier_thri(struct uart_omap_port *up)
static void serial_omap_start_tx(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
struct omap_uart_port_info *pdata = up->pdev->dev.platform_data;
struct circ_buf *xmit;
unsigned int start;
@@ -375,7 +380,7 @@ static void serial_omap_start_tx(struct uart_port *port)
static void serial_omap_throttle(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
unsigned long flags;
pm_runtime_get_sync(&up->pdev->dev);
@@ -389,7 +394,7 @@ static void serial_omap_throttle(struct uart_port *port)
static void serial_omap_unthrottle(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
unsigned long flags;
pm_runtime_get_sync(&up->pdev->dev);
@@ -477,7 +482,7 @@ static inline irqreturn_t serial_omap_irq(int irq, void *dev_id)
static unsigned int serial_omap_tx_empty(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
unsigned long flags = 0;
unsigned int ret = 0;
@@ -492,7 +497,7 @@ static unsigned int serial_omap_tx_empty(struct uart_port *port)
static unsigned int serial_omap_get_mctrl(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
unsigned int status;
unsigned int ret = 0;
@@ -515,7 +520,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
unsigned char mcr = 0, old_mcr;
dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line);
@@ -541,7 +546,7 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void serial_omap_break_ctl(struct uart_port *port, int break_state)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
unsigned long flags = 0;
dev_dbg(up->port.dev, "serial_omap_break_ctl+%d\n", up->port.line);
@@ -558,7 +563,7 @@ static void serial_omap_break_ctl(struct uart_port *port, int break_state)
static int serial_omap_startup(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
unsigned long flags = 0;
int retval;
@@ -631,7 +636,7 @@ static int serial_omap_startup(struct uart_port *port)
static void serial_omap_shutdown(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
unsigned long flags = 0;
dev_dbg(up->port.dev, "serial_omap_shutdown+%d\n", up->port.line);
@@ -673,7 +678,7 @@ static void serial_omap_shutdown(struct uart_port *port)
static int serial_omap_alloc_xmit(struct uart_port *port, struct circ_buf *xmit)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
if (up->use_dma) {
xmit->buf = dma_alloc_coherent(NULL, UART_XMIT_SIZE,
@@ -688,7 +693,7 @@ static int serial_omap_alloc_xmit(struct uart_port *port, struct circ_buf *xmit)
static void serial_omap_free_xmit(struct uart_port *port, struct circ_buf *xmit)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
if (up->use_dma) {
dma_free_coherent(NULL, UART_XMIT_SIZE,
@@ -710,7 +715,7 @@ static void
serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
unsigned char cval = 0;
unsigned long flags = 0;
unsigned int baud, quot;
@@ -963,7 +968,7 @@ static void
serial_omap_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
unsigned char efr;
dev_dbg(up->port.dev, "serial_omap_pm+%d\n", up->port.line);
@@ -1002,7 +1007,7 @@ static int serial_omap_request_port(struct uart_port *port)
static void serial_omap_config_port(struct uart_port *port, int flags)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",
up->port.line);
@@ -1021,7 +1026,7 @@ serial_omap_verify_port(struct uart_port *port, struct serial_struct *ser)
static const char *
serial_omap_type(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
dev_dbg(up->port.dev, "serial_omap_type+%d\n", up->port.line);
return up->name;
@@ -1064,7 +1069,7 @@ static inline void wait_for_xmitr(struct uart_omap_port *up)
static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
pm_runtime_get_sync(&up->pdev->dev);
wait_for_xmitr(up);
@@ -1074,7 +1079,7 @@ static void serial_omap_poll_put_char(struct uart_port *port, unsigned char ch)
static int serial_omap_poll_get_char(struct uart_port *port)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
unsigned int status;
pm_runtime_get_sync(&up->pdev->dev);
@@ -1097,7 +1102,7 @@ static struct uart_driver serial_omap_reg;
static void serial_omap_console_putchar(struct uart_port *port, int ch)
{
- struct uart_omap_port *up = (struct uart_omap_port *)port;
+ struct uart_omap_port *up = serial_omap_port(port);
wait_for_xmitr(up);
serial_out(up, UART_TX, ch);
@@ -1377,7 +1382,7 @@ static void serial_omap_continue_tx(struct uart_omap_port *up)
static void uart_tx_dma_callback(int lch, u16 ch_status, void *data)
{
- struct uart_omap_port *up = (struct uart_omap_port *)data;
+ struct uart_omap_port *up = serial_omap_port(data);
struct circ_buf *xmit = &up->port.state->xmit;
xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \
--
1.7.4.4
^ permalink raw reply related
* [RFC 21/24] SERIAL: omap: use tx buffer allocation API
From: Russell King @ 2012-10-06 12:46 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
Rather than working around serial_core, use the newly provided buffer
allocation API to allow a saner method to manage this buffer.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/omap-serial.c | 38 +++++++++++++++++++++++++++++---------
1 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index b497187..6054fc8 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -604,11 +604,6 @@ static int serial_omap_startup(struct uart_port *port)
up->msr_saved_flags = 0;
if (up->use_dma) {
- free_page((unsigned long)up->port.state->xmit.buf);
- up->port.state->xmit.buf = dma_alloc_coherent(NULL,
- UART_XMIT_SIZE,
- (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
- 0);
init_timer(&(up->uart_dma.rx_timer));
up->uart_dma.rx_timer.function = serial_omap_rxdma_poll;
up->uart_dma.rx_timer.data = up->port.line;
@@ -665,10 +660,6 @@ static void serial_omap_shutdown(struct uart_port *port)
if (serial_in(up, UART_LSR) & UART_LSR_DR)
(void) serial_in(up, UART_RX);
if (up->use_dma) {
- dma_free_coherent(up->port.dev,
- UART_XMIT_SIZE, up->port.state->xmit.buf,
- up->uart_dma.tx_buf_dma_phys);
- up->port.state->xmit.buf = NULL;
serial_omap_stop_rx(port);
dma_free_coherent(up->port.dev,
up->uart_dma.rx_buf_size, up->uart_dma.rx_buf,
@@ -680,6 +671,33 @@ static void serial_omap_shutdown(struct uart_port *port)
free_irq(up->port.irq, up);
}
+static int serial_omap_alloc_xmit(struct uart_port *port, struct circ_buf *xmit)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+ if (up->use_dma) {
+ xmit->buf = dma_alloc_coherent(NULL, UART_XMIT_SIZE,
+ &up->uart_dma.tx_buf_dma_phys, 0);
+ } else {
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ xmit->buf = (unsigned char *)page;
+ }
+
+ return xmit->buf ? 0 : -ENOMEM;
+}
+
+static void serial_omap_free_xmit(struct uart_port *port, struct circ_buf *xmit)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+
+ if (up->use_dma) {
+ dma_free_coherent(NULL, UART_XMIT_SIZE,
+ xmit->buf, up->uart_dma.tx_buf_dma_phys);
+ } else {
+ free_page((unsigned long)xmit->buf);
+ }
+}
+
static void serial_omap_uart_qos_work(struct work_struct *work)
{
struct uart_omap_port *up = container_of(work, struct uart_omap_port,
@@ -1193,6 +1211,8 @@ static struct uart_ops serial_omap_pops = {
.break_ctl = serial_omap_break_ctl,
.startup = serial_omap_startup,
.shutdown = serial_omap_shutdown,
+ .alloc_xmit = serial_omap_alloc_xmit,
+ .free_xmit = serial_omap_free_xmit,
.set_termios = serial_omap_set_termios,
.pm = serial_omap_pm,
.type = serial_omap_type,
--
1.7.4.4
^ permalink raw reply related
* [RFC 20/24] SERIAL: core: add xmit buffer allocation callbacks
From: Russell King @ 2012-10-06 12:45 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
This allows drivers (such as OMAP serial) to allocate and free their
transmit buffers in a sane manner, rather than working around the
buffer allocation provided by serial_core.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/serial_core.c | 23 ++++++++++++++++-------
include/linux/serial_core.h | 2 ++
2 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 4dd609e..53274ae 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -147,12 +147,18 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
* buffer.
*/
if (!state->xmit.buf) {
- /* This is protected by the per port mutex */
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
+ if (uport->ops->alloc_xmit) {
+ retval = uport->ops->alloc_xmit(uport, &state->xmit);
+ if (retval)
+ return retval;
+ } else {
+ /* This is protected by the per port mutex */
+ page = get_zeroed_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
- state->xmit.buf = (unsigned char *) page;
+ state->xmit.buf = (unsigned char *) page;
+ }
uart_circ_clear(&state->xmit);
}
@@ -257,7 +263,10 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
* Free the transmit buffer page.
*/
if (state->xmit.buf) {
- free_page((unsigned long)state->xmit.buf);
+ if (uport->ops->free_xmit)
+ uport->ops->free_xmit(uport, &state->xmit);
+ else
+ free_page((unsigned long)state->xmit.buf);
state->xmit.buf = NULL;
}
}
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index b17d4c9..ebe9af1 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -248,6 +248,8 @@ struct uart_ops {
void (*break_ctl)(struct uart_port *, int ctl);
int (*startup)(struct uart_port *);
void (*shutdown)(struct uart_port *);
+ int (*alloc_xmit)(struct uart_port *, struct circ_buf *);
+ void (*free_xmit)(struct uart_port *, struct circ_buf *);
void (*flush_buffer)(struct uart_port *);
void (*set_termios)(struct uart_port *, struct ktermios *new,
struct ktermios *old);
--
1.7.4.4
^ permalink raw reply related
* [RFC 19/24] SERIAL: omap: simplify (2)
From: Russell King @ 2012-10-06 12:45 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
Simplify:
- set ECB
...
- LCR mode A
- clear TCRTLR
- LCR mode B
- clear ECB
- set ECB and update other bits
- LCR mode A
- update XONANY
to:
- set ECB
...
- LCR mode B
- set ECB and update other bits
- LCR mode A
- update XONANY and clear TCRTLR
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/omap-serial.c | 11 +++--------
1 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index e786eac..b497187 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -896,11 +896,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS);
}
- /* Disable access to TCR/TLR */
- serial_out(up, UART_MCR, up->mcr);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_out(up, UART_EFR, up->efr);
-
/* clear SW control mode bits */
up->efr &= OMAP_UART_SW_CLR;
@@ -920,9 +915,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
if (termios->c_iflag & IXOFF)
up->efr |= OMAP_UART_SW_TX;
- serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-
/*
* IXANY Flag:
* Enable any character to restart output.
@@ -934,6 +926,9 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
else
up->mcr &= ~UART_MCR_XONANY;
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_out(up, UART_MCR, up->mcr);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, up->efr);
--
1.7.4.4
^ permalink raw reply related
* [RFC 18/24] SERIAL: omap: move xon/xoff setting earlier
From: Russell King @ 2012-10-06 12:45 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
Take advantage of the switch to mode B for accessing the TCR register,
and move the xon/xoff configuration there. This allows further
simplication of this sequence.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/omap-serial.c | 13 +++++++------
1 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 22877ac..e786eac 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -871,16 +871,20 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
else
serial_out(up, UART_OMAP_MDR1, up->mdr1);
- /* Enable access to TCR/TLR */
+ /* Configure flow control */
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+ /* XON1/XOFF1 accessible mode B, TCRTLR=0, ECB=0 */
+ serial_out(up, UART_XON1, termios->c_cc[VSTART]);
+ serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
+
+ /* Enable access to TCR/TLR */
serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
- /* Hardware Flow Control Configuration */
-
if (termios->c_cflag & CRTSCTS) {
/* Enable AUTORTS and AUTOCTS */
up->efr |= UART_EFR_CTS | UART_EFR_RTS;
@@ -897,9 +901,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, up->efr);
- serial_out(up, UART_XON1, termios->c_cc[VSTART]);
- serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
-
/* clear SW control mode bits */
up->efr &= OMAP_UART_SW_CLR;
--
1.7.4.4
^ permalink raw reply related
* [RFC 17/24] SERIAL: omap: always set TCR
From: Russell King @ 2012-10-06 12:44 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
We always setup the TCR register in the software flow control path,
and when hardware flow control is enabled. Remove this redundant
setup, and place it before we setup any hardware flow control.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/omap-serial.c | 25 ++++++++++---------------
1 files changed, 10 insertions(+), 15 deletions(-)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index da0d4b1..22877ac 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -871,30 +871,29 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
else
serial_out(up, UART_OMAP_MDR1, up->mdr1);
- /* Hardware Flow Control Configuration */
+ /* Enable access to TCR/TLR */
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+ serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
- if (termios->c_cflag & CRTSCTS) {
- /* Enable access to TCR/TLR */
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
- serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+ serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
- serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+ /* Hardware Flow Control Configuration */
+ if (termios->c_cflag & CRTSCTS) {
/* Enable AUTORTS and AUTOCTS */
up->efr |= UART_EFR_CTS | UART_EFR_RTS;
/* Ensure MCR RTS is asserted */
up->mcr |= UART_MCR_RTS;
-
- /* Disable access to TCR/TLR */
- serial_out(up, UART_MCR, up->mcr);
} else {
/* Disable AUTORTS and AUTOCTS */
up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS);
}
+ /* Disable access to TCR/TLR */
+ serial_out(up, UART_MCR, up->mcr);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, up->efr);
@@ -934,10 +933,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
else
up->mcr &= ~UART_MCR_XONANY;
- serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
serial_out(up, UART_MCR, up->mcr);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, up->efr);
--
1.7.4.4
^ permalink raw reply related
* [RFC 16/24] SERIAL: omap: simplify
From: Russell King @ 2012-10-06 12:44 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
We have the sequence:
- LCR mode B
- write EFR with ECB clear
- LCR mode normal
- LCR mode B
- write EFR with ECB clear
This can be simplified to just two writes:
- LCR mode B
- write EFR with ECB clear
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/omap-serial.c | 8 --------
1 files changed, 0 insertions(+), 8 deletions(-)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 70c9661..da0d4b1 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -890,19 +890,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
/* Disable access to TCR/TLR */
serial_out(up, UART_MCR, up->mcr);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_out(up, UART_EFR, up->efr);
- serial_out(up, UART_LCR, cval);
} else {
/* Disable AUTORTS and AUTOCTS */
up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS);
-
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_out(up, UART_EFR, up->efr);
- serial_out(up, UART_LCR, cval);
}
- /* Software Flow Control Configuration */
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, up->efr);
--
1.7.4.4
^ permalink raw reply related
* [RFC 15/24] SERIAL: omap: don't read back LCR/MCR/EFR
From: Russell King @ 2012-10-06 12:44 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
There's really no reason to read back these registers while setting
the termios modes, provided we keep our cached copies up to date.
Remove these readbacks.
This has the benefit that we know that the EFR_ECB and MCR_TCRTLR
bits will always be clear, so we don't need to keep masking these
bits throughout the code.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/omap-serial.c | 13 ++++++-------
1 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index b6f8b88..70c9661 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -885,8 +885,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
/* Enable AUTORTS and AUTOCTS */
up->efr |= UART_EFR_CTS | UART_EFR_RTS;
+ /* Ensure MCR RTS is asserted */
+ up->mcr |= UART_MCR_RTS;
+
/* Disable access to TCR/TLR */
- serial_out(up, UART_MCR, up->mcr | UART_MCR_RTS);
+ serial_out(up, UART_MCR, up->mcr);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, up->efr);
serial_out(up, UART_LCR, cval);
@@ -900,10 +903,8 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
}
/* Software Flow Control Configuration */
- up->lcr = serial_in(up, UART_LCR);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- up->efr = serial_in(up, UART_EFR);
- serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
+ serial_out(up, UART_EFR, up->efr);
serial_out(up, UART_XON1, termios->c_cc[VSTART]);
serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
@@ -930,8 +931,6 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
- up->mcr = serial_in(up, UART_MCR);
-
/*
* IXANY Flag:
* Enable any character to restart output.
@@ -947,7 +946,7 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
- serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
+ serial_out(up, UART_MCR, up->mcr);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_out(up, UART_EFR, up->efr);
serial_out(up, UART_LCR, up->lcr);
--
1.7.4.4
^ permalink raw reply related
* [RFC 14/24] SERIAL: omap: serial_omap_configure_xonxoff() contents into set_termios
From: Russell King @ 2012-10-06 12:43 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/omap-serial.c | 109 ++++++++++++++++++--------------------
1 files changed, 51 insertions(+), 58 deletions(-)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index cc1a907..b6f8b88 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -680,63 +680,6 @@ static void serial_omap_shutdown(struct uart_port *port)
free_irq(up->port.irq, up);
}
-static inline void
-serial_omap_configure_xonxoff
- (struct uart_omap_port *up, struct ktermios *termios)
-{
- up->lcr = serial_in(up, UART_LCR);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- up->efr = serial_in(up, UART_EFR);
- serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
-
- serial_out(up, UART_XON1, termios->c_cc[VSTART]);
- serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
-
- /* clear SW control mode bits */
- up->efr &= OMAP_UART_SW_CLR;
-
- /*
- * IXON Flag:
- * Enable XON/XOFF flow control on input.
- * Receiver compares XON1, XOFF1.
- */
- if (termios->c_iflag & IXON)
- up->efr |= OMAP_UART_SW_RX;
-
- /*
- * IXOFF Flag:
- * Enable XON/XOFF flow control on output.
- * Transmit XON1, XOFF1
- */
- if (termios->c_iflag & IXOFF)
- up->efr |= OMAP_UART_SW_TX;
-
- serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
-
- up->mcr = serial_in(up, UART_MCR);
-
- /*
- * IXANY Flag:
- * Enable any character to restart output.
- * Operation resumes after receiving any
- * character after recognition of the XOFF character
- */
- if (termios->c_iflag & IXANY)
- up->mcr |= UART_MCR_XONANY;
- else
- up->mcr &= ~UART_MCR_XONANY;
-
- serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
- serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
- serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_out(up, UART_EFR, up->efr);
- serial_out(up, UART_LCR, up->lcr);
-}
-
static void serial_omap_uart_qos_work(struct work_struct *work)
{
struct uart_omap_port *up = container_of(work, struct uart_omap_port,
@@ -957,7 +900,57 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
}
/* Software Flow Control Configuration */
- serial_omap_configure_xonxoff(up, termios);
+ up->lcr = serial_in(up, UART_LCR);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ up->efr = serial_in(up, UART_EFR);
+ serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
+
+ serial_out(up, UART_XON1, termios->c_cc[VSTART]);
+ serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
+
+ /* clear SW control mode bits */
+ up->efr &= OMAP_UART_SW_CLR;
+
+ /*
+ * IXON Flag:
+ * Enable XON/XOFF flow control on input.
+ * Receiver compares XON1, XOFF1.
+ */
+ if (termios->c_iflag & IXON)
+ up->efr |= OMAP_UART_SW_RX;
+
+ /*
+ * IXOFF Flag:
+ * Enable XON/XOFF flow control on output.
+ * Transmit XON1, XOFF1
+ */
+ if (termios->c_iflag & IXOFF)
+ up->efr |= OMAP_UART_SW_TX;
+
+ serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+
+ up->mcr = serial_in(up, UART_MCR);
+
+ /*
+ * IXANY Flag:
+ * Enable any character to restart output.
+ * Operation resumes after receiving any
+ * character after recognition of the XOFF character
+ */
+ if (termios->c_iflag & IXANY)
+ up->mcr |= UART_MCR_XONANY;
+ else
+ up->mcr &= ~UART_MCR_XONANY;
+
+ serial_out(up, UART_MCR, up->mcr | UART_MCR_TCRTLR);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A);
+ serial_out(up, UART_MCR, up->mcr & ~UART_MCR_TCRTLR);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ serial_out(up, UART_EFR, up->efr);
+ serial_out(up, UART_LCR, up->lcr);
serial_omap_set_mctrl(&up->port, up->port.mctrl);
--
1.7.4.4
^ permalink raw reply related
* [RFC 13/24] SERIAL: omap: configure xon/xoff before setting modem control lines
From: Russell King @ 2012-10-06 12:43 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/omap-serial.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index ab5a5e0..cc1a907 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -956,10 +956,11 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_out(up, UART_LCR, cval);
}
- serial_omap_set_mctrl(&up->port, up->port.mctrl);
/* Software Flow Control Configuration */
serial_omap_configure_xonxoff(up, termios);
+ serial_omap_set_mctrl(&up->port, up->port.mctrl);
+
spin_unlock_irqrestore(&up->port.lock, flags);
pm_runtime_put(&up->pdev->dev);
dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->port.line);
--
1.7.4.4
^ permalink raw reply related
* [RFC 12/24] SERIAL: omap: fix hardware assisted flow control
From: Russell King @ 2012-10-06 12:43 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
When the UART device has hardware flow control enabled, it ignores the
MCR RTS bit in the MCR register, and keeps RTS asserted as long as we
continue to read characters from the UART receiver FIFO. This means
that when the TTY buffers become full, the UART doesn't tell the remote
end to stop sending, which causes the TTY layer to start dropping
characters.
A similar problem exists with software flow control. We need the FIFO
register to fill when software flow control is enabled to provoke the
UART to send the XOFF character.
Fix this by implementing the throttle/unthrottle callbacks, and use
these to disable receiver interrupts. This in turn means that the UART
FIFO will fill, which will then cause the UART's hardware to deassert
the RTS signal and/or send the XOFF character, stopping the remote end.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/omap-serial.c | 31 +++++++++++++++++++++++++++++++
1 files changed, 31 insertions(+), 0 deletions(-)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 6314827..ab5a5e0 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -373,6 +373,34 @@ static void serial_omap_start_tx(struct uart_port *port)
omap_start_dma(up->uart_dma.tx_dma_channel);
}
+static void serial_omap_throttle(struct uart_port *port)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ unsigned long flags;
+
+ pm_runtime_get_sync(&up->pdev->dev);
+ spin_lock_irqsave(&up->port.lock, flags);
+ up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
+ serial_out(up, UART_IER, up->ier);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ pm_runtime_mark_last_busy(&up->pdev->dev);
+ pm_runtime_put_autosuspend(&up->pdev->dev);
+}
+
+static void serial_omap_unthrottle(struct uart_port *port)
+{
+ struct uart_omap_port *up = (struct uart_omap_port *)port;
+ unsigned long flags;
+
+ pm_runtime_get_sync(&up->pdev->dev);
+ spin_lock_irqsave(&up->port.lock, flags);
+ up->ier |= UART_IER_RLSI | UART_IER_RDI;
+ serial_out(up, UART_IER, up->ier);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ pm_runtime_mark_last_busy(&up->pdev->dev);
+ pm_runtime_put_autosuspend(&up->pdev->dev);
+}
+
static unsigned int check_modem_status(struct uart_omap_port *up)
{
unsigned int status;
@@ -985,6 +1013,7 @@ static void serial_omap_config_port(struct uart_port *port, int flags)
dev_dbg(up->port.dev, "serial_omap_config_port+%d\n",
up->port.line);
up->port.type = PORT_OMAP;
+ up->port.flags |= UPF_SOFT_FLOW | UPF_HARD_FLOW;
}
static int
@@ -1181,6 +1210,8 @@ static struct uart_ops serial_omap_pops = {
.get_mctrl = serial_omap_get_mctrl,
.stop_tx = serial_omap_stop_tx,
.start_tx = serial_omap_start_tx,
+ .throttle = serial_omap_throttle,
+ .unthrottle = serial_omap_unthrottle,
.stop_rx = serial_omap_stop_rx,
.enable_ms = serial_omap_enable_ms,
.break_ctl = serial_omap_break_ctl,
--
1.7.4.4
^ permalink raw reply related
* [RFC 11/24] SERIAL: core: add throttle/unthrottle callbacks for hardware assisted flow control
From: Russell King @ 2012-10-06 12:42 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
Add two callbacks for hardware assisted flow control; we need to know
when the tty layers want us to stop and restart due to their buffer
levels.
Call a driver specific throttle/unthrottle function if and only if the
driver indicates that it is using an enabled hardware assisted flow
control method, otherwise fall back to the non-hardware assisted
methods.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/serial_core.c | 31 +++++++++++++++++++++++++++----
include/linux/serial_core.h | 2 ++
2 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 02b10bc..4dd609e 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -610,27 +610,50 @@ static void uart_send_xchar(struct tty_struct *tty, char ch)
static void uart_throttle(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ struct uart_port *port = state->uart_port;
+ uint32_t mask = 0;
if (I_IXOFF(tty))
+ mask |= UPF_SOFT_FLOW;
+ if (tty->termios->c_cflag & CRTSCTS)
+ mask |= UPF_HARD_FLOW;
+
+ if (port->flags & mask) {
+ port->ops->throttle(port);
+ mask &= ~port->flags;
+ }
+
+ if (mask & UPF_SOFT_FLOW)
uart_send_xchar(tty, STOP_CHAR(tty));
- if (tty->termios->c_cflag & CRTSCTS)
- uart_clear_mctrl(state->uart_port, TIOCM_RTS);
+ if (mask & UPF_HARD_FLOW)
+ uart_clear_mctrl(port, TIOCM_RTS);
}
static void uart_unthrottle(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
+ uint32_t mask = 0;
- if (I_IXOFF(tty)) {
+ if (I_IXOFF(tty))
+ mask |= UPF_SOFT_FLOW;
+ if (tty->termios->c_cflag & CRTSCTS)
+ mask |= UPF_HARD_FLOW;
+
+ if (port->flags & mask) {
+ port->ops->unthrottle(port);
+ mask &= ~port->flags;
+ }
+
+ if (mask & UPF_SOFT_FLOW) {
if (port->x_char)
port->x_char = 0;
else
uart_send_xchar(tty, START_CHAR(tty));
}
- if (tty->termios->c_cflag & CRTSCTS)
+ if (mask & UPF_HARD_FLOW)
uart_set_mctrl(port, TIOCM_RTS);
}
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 8e8500e..b17d4c9 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -240,6 +240,8 @@ struct uart_ops {
unsigned int (*get_mctrl)(struct uart_port *);
void (*stop_tx)(struct uart_port *);
void (*start_tx)(struct uart_port *);
+ void (*throttle)(struct uart_port *);
+ void (*unthrottle)(struct uart_port *);
void (*send_xchar)(struct uart_port *, char ch);
void (*stop_rx)(struct uart_port *);
void (*enable_ms)(struct uart_port *);
--
1.7.4.4
^ permalink raw reply related
* [RFC 10/24] SERIAL: core: add hardware assisted h/w flow control support
From: Russell King @ 2012-10-06 12:42 UTC (permalink / raw)
To: Tony Lindgren, Alan Cox, Greg Kroah-Hartman
Cc: linux-arm-kernel, linux-omap, linux-serial
In-Reply-To: <20121006123803.GD15246@n2100.arm.linux.org.uk>
Ports which are handling h/w flow control in hardware must not have
their RTS state altered depending on the tty's hardware-stopped state.
Avoid this additional logic when setting the termios state.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
drivers/tty/serial/serial_core.c | 7 +++++++
include/linux/serial_core.h | 2 ++
2 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index ec6d029..02b10bc 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1239,6 +1239,13 @@ static void uart_set_termios(struct tty_struct *tty,
uart_set_mctrl(uport, mask);
}
+ /*
+ * If the port is doing h/w assisted flow control, do nothing.
+ * We assume that tty->hw_stopped has never been set.
+ */
+ if (uport->flags & UPF_HARD_FLOW)
+ return;
+
/* Handle turning off CRTSCTS */
if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
spin_lock_irqsave(&uport->lock, flags);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index be3f8d9..8e8500e 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -356,6 +356,8 @@ struct uart_port {
#define UPF_BUGGY_UART ((__force upf_t) (1 << 14))
#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15))
#define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16))
+/* Port has hardware-assisted h/w flow control (iow, auto-RTS *not* auto-CTS) */
+#define UPF_HARD_FLOW ((__force upf_t) (1 << 21))
/* Port has hardware-assisted s/w flow control */
#define UPF_SOFT_FLOW ((__force upf_t) (1 << 22))
#define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
--
1.7.4.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox