summaryrefslogtreecommitdiff
path: root/drivers/tty
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/Kconfig25
-rw-r--r--drivers/tty/amiserial.c11
-rw-r--r--drivers/tty/goldfish.c3
-rw-r--r--drivers/tty/hvc/hvc_iucv.c22
-rw-r--r--drivers/tty/hvc/hvc_opal.c2
-rw-r--r--drivers/tty/hvc/hvc_xen.c2
-rw-r--r--drivers/tty/hvc/hvsi_lib.c2
-rw-r--r--drivers/tty/ipwireless/hardware.c4
-rw-r--r--drivers/tty/mips_ejtag_fdc.c8
-rw-r--r--drivers/tty/moxa.c253
-rw-r--r--drivers/tty/mxser.c9
-rw-r--r--drivers/tty/n_gsm.c198
-rw-r--r--drivers/tty/n_hdlc.c1
-rw-r--r--drivers/tty/n_tty.c234
-rw-r--r--drivers/tty/pty.c2
-rw-r--r--drivers/tty/serdev/core.c15
-rw-r--r--drivers/tty/serdev/serdev-ttyport.c9
-rw-r--r--drivers/tty/serial/8250/8250.h38
-rw-r--r--drivers/tty/serial/8250/8250_alpha.c21
-rw-r--r--drivers/tty/serial/8250/8250_aspeed_vuart.c5
-rw-r--r--drivers/tty/serial/8250/8250_bcm2835aux.c53
-rw-r--r--drivers/tty/serial/8250/8250_bcm7271.c122
-rw-r--r--drivers/tty/serial/8250/8250_core.c479
-rw-r--r--drivers/tty/serial/8250/8250_dma.c48
-rw-r--r--drivers/tty/serial/8250/8250_dw.c159
-rw-r--r--drivers/tty/serial/8250/8250_dwlib.c5
-rw-r--r--drivers/tty/serial/8250/8250_dwlib.h33
-rw-r--r--drivers/tty/serial/8250/8250_early.c15
-rw-r--r--drivers/tty/serial/8250/8250_em.c2
-rw-r--r--drivers/tty/serial/8250/8250_exar.c1001
-rw-r--r--drivers/tty/serial/8250/8250_fintek.c16
-rw-r--r--drivers/tty/serial/8250/8250_fsl.c10
-rw-r--r--drivers/tty/serial/8250/8250_ingenic.c2
-rw-r--r--drivers/tty/serial/8250/8250_ioc3.c2
-rw-r--r--drivers/tty/serial/8250/8250_lpc18xx.c2
-rw-r--r--drivers/tty/serial/8250/8250_men_mcb.c2
-rw-r--r--drivers/tty/serial/8250/8250_mtk.c16
-rw-r--r--drivers/tty/serial/8250/8250_ni.c461
-rw-r--r--drivers/tty/serial/8250/8250_of.c40
-rw-r--r--drivers/tty/serial/8250/8250_omap.c135
-rw-r--r--drivers/tty/serial/8250/8250_parisc.c1
-rw-r--r--drivers/tty/serial/8250/8250_pci.c181
-rw-r--r--drivers/tty/serial/8250/8250_pci1xxxx.c112
-rw-r--r--drivers/tty/serial/8250/8250_pcilib.c16
-rw-r--r--drivers/tty/serial/8250/8250_pcilib.h2
-rw-r--r--drivers/tty/serial/8250/8250_platform.c414
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c55
-rw-r--r--drivers/tty/serial/8250/8250_port.c241
-rw-r--r--drivers/tty/serial/8250/8250_pxa.c20
-rw-r--r--drivers/tty/serial/8250/8250_rsa.c130
-rw-r--r--drivers/tty/serial/8250/8250_tegra.c2
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c2
-rw-r--r--drivers/tty/serial/8250/Kconfig18
-rw-r--r--drivers/tty/serial/8250/Makefile9
-rw-r--r--drivers/tty/serial/8250/serial_cs.c1
-rw-r--r--drivers/tty/serial/Kconfig101
-rw-r--r--drivers/tty/serial/Makefile6
-rw-r--r--drivers/tty/serial/altera_jtaguart.c16
-rw-r--r--drivers/tty/serial/altera_uart.c15
-rw-r--r--drivers/tty/serial/amba-pl010.c2
-rw-r--r--drivers/tty/serial/amba-pl011.c353
-rw-r--r--drivers/tty/serial/ar933x_uart.c20
-rw-r--r--drivers/tty/serial/arc_uart.c8
-rw-r--r--drivers/tty/serial/atmel_serial.c190
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c9
-rw-r--r--drivers/tty/serial/clps711x.c14
-rw-r--r--drivers/tty/serial/cpm_uart.c24
-rw-r--r--drivers/tty/serial/digicolor-usart.c14
-rw-r--r--drivers/tty/serial/dz.c13
-rw-r--r--drivers/tty/serial/earlycon.c23
-rw-r--r--drivers/tty/serial/esp32_acm.c3
-rw-r--r--drivers/tty/serial/esp32_uart.c3
-rw-r--r--drivers/tty/serial/fsl_linflexuart.c19
-rw-r--r--drivers/tty/serial/fsl_lpuart.c571
-rw-r--r--drivers/tty/serial/icom.c34
-rw-r--r--drivers/tty/serial/imx.c329
-rw-r--r--drivers/tty/serial/ip22zilog.c26
-rw-r--r--drivers/tty/serial/jsm/jsm_cls.c29
-rw-r--r--drivers/tty/serial/jsm/jsm_neo.c38
-rw-r--r--drivers/tty/serial/kgdb_nmi.c381
-rw-r--r--drivers/tty/serial/kgdboc.c38
-rw-r--r--drivers/tty/serial/lantiq.c2
-rw-r--r--drivers/tty/serial/liteuart.c6
-rw-r--r--drivers/tty/serial/lpc32xx_hs.c2
-rw-r--r--drivers/tty/serial/ma35d1_serial.c17
-rw-r--r--drivers/tty/serial/max3100.c340
-rw-r--r--drivers/tty/serial/max310x.c39
-rw-r--r--drivers/tty/serial/mcf.c4
-rw-r--r--drivers/tty/serial/men_z135_uart.c28
-rw-r--r--drivers/tty/serial/meson_uart.c14
-rw-r--r--drivers/tty/serial/milbeaut_usio.c17
-rw-r--r--drivers/tty/serial/mpc52xx_uart.c5
-rw-r--r--drivers/tty/serial/msm_serial.c130
-rw-r--r--drivers/tty/serial/mux.c2
-rw-r--r--drivers/tty/serial/mvebu-uart.c8
-rw-r--r--drivers/tty/serial/mxs-auart.c25
-rw-r--r--drivers/tty/serial/omap-serial.c3
-rw-r--r--drivers/tty/serial/owl-uart.c3
-rw-r--r--drivers/tty/serial/pch_uart.c22
-rw-r--r--drivers/tty/serial/pic32_uart.c19
-rw-r--r--drivers/tty/serial/pmac_zilog.c33
-rw-r--r--drivers/tty/serial/qcom_geni_serial.c319
-rw-r--r--drivers/tty/serial/rda-uart.c19
-rw-r--r--drivers/tty/serial/rp2.c14
-rw-r--r--drivers/tty/serial/sa1100.c6
-rw-r--r--drivers/tty/serial/samsung_tty.c120
-rw-r--r--drivers/tty/serial/sb1250-duart.c13
-rw-r--r--drivers/tty/serial/sc16is7xx.c600
-rw-r--r--drivers/tty/serial/sc16is7xx.h41
-rw-r--r--drivers/tty/serial/sc16is7xx_i2c.c67
-rw-r--r--drivers/tty/serial/sc16is7xx_spi.c90
-rw-r--r--drivers/tty/serial/sccnxp.c20
-rw-r--r--drivers/tty/serial/serial-tegra.c45
-rw-r--r--drivers/tty/serial/serial_base.h16
-rw-r--r--drivers/tty/serial/serial_base_bus.c39
-rw-r--r--drivers/tty/serial/serial_core.c591
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.c63
-rw-r--r--drivers/tty/serial/serial_mctrl_gpio.h27
-rw-r--r--drivers/tty/serial/serial_port.c28
-rw-r--r--drivers/tty/serial/serial_txx9.c2
-rw-r--r--drivers/tty/serial/sh-sci.c352
-rw-r--r--drivers/tty/serial/sifive.c12
-rw-r--r--drivers/tty/serial/sprd_serial.c63
-rw-r--r--drivers/tty/serial/st-asc.c16
-rw-r--r--drivers/tty/serial/stm32-usart.c62
-rw-r--r--drivers/tty/serial/sunhv.c37
-rw-r--r--drivers/tty/serial/sunplus-uart.c18
-rw-r--r--drivers/tty/serial/sunsab.c32
-rw-r--r--drivers/tty/serial/sunsu.c232
-rw-r--r--drivers/tty/serial/sunzilog.c29
-rw-r--r--drivers/tty/serial/tegra-tcu.c12
-rw-r--r--drivers/tty/serial/tegra-utc.c625
-rw-r--r--drivers/tty/serial/timbuart.c19
-rw-r--r--drivers/tty/serial/uartlite.c15
-rw-r--r--drivers/tty/serial/ucc_uart.c24
-rw-r--r--drivers/tty/serial/xilinx_uartps.c55
-rw-r--r--drivers/tty/serial/zs.c13
-rw-r--r--drivers/tty/synclink_gt.c9
-rw-r--r--drivers/tty/sysrq.c40
-rw-r--r--drivers/tty/tty_audit.c10
-rw-r--r--drivers/tty/tty_io.c37
-rw-r--r--drivers/tty/tty_ldisc.c6
-rw-r--r--drivers/tty/tty_ldsem.c17
-rw-r--r--drivers/tty/ttynull.c1
-rw-r--r--drivers/tty/vcc.c6
-rw-r--r--drivers/tty/vt/conmakehash.c9
-rw-r--r--drivers/tty/vt/keyboard.c6
-rw-r--r--drivers/tty/vt/selection.c13
-rw-r--r--drivers/tty/vt/vc_screen.c4
-rw-r--r--drivers/tty/vt/vt.c18
150 files changed, 7015 insertions, 4566 deletions
diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig
index a45d423ad10f..149f3d53b760 100644
--- a/drivers/tty/Kconfig
+++ b/drivers/tty/Kconfig
@@ -210,7 +210,7 @@ config SERIAL_NONSTANDARD
config MOXA_INTELLIO
tristate "Moxa Intellio support"
- depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
+ depends on SERIAL_NONSTANDARD && PCI
select FW_LOADER
help
Say Y here if you have a Moxa Intellio multiport serial card.
@@ -220,7 +220,7 @@ config MOXA_INTELLIO
config MOXA_SMARTIO
tristate "Moxa SmartIO support v. 2.0"
- depends on SERIAL_NONSTANDARD && PCI
+ depends on SERIAL_NONSTANDARD && PCI && HAS_IOPORT
help
Say Y here if you have a Moxa SmartIO multiport serial card and/or
want to help develop a new version of this driver.
@@ -302,7 +302,7 @@ config GOLDFISH_TTY_EARLY_CONSOLE
config IPWIRELESS
tristate "IPWireless 3G UMTS PCMCIA card support"
- depends on PCMCIA && NETDEVICES
+ depends on PCMCIA && NETDEVICES && HAS_IOPORT
select PPP
help
This is a driver for 3G UMTS PCMCIA card from IPWireless company. In
@@ -383,7 +383,24 @@ config NULL_TTY
available or desired.
In order to use this driver, you should redirect the console to this
- TTY, or boot the kernel with console=ttynull.
+ TTY, boot the kernel with console=ttynull, or enable
+ NULL_TTY_DEFAULT_CONSOLE.
+
+ If unsure, say N.
+
+config NULL_TTY_DEFAULT_CONSOLE
+ bool "Support for console on ttynull"
+ depends on NULL_TTY=y && !VT_CONSOLE
+ help
+ Say Y here if you want the NULL TTY to be used as a /dev/console
+ device by default.
+
+ For example, it might be useful to prevent a VT-less kernel from
+ writing the system log to a random device connected to the serial
+ port.
+
+ Another console driver still might get preferred via the command
+ line, SPCR, or the device tree.
If unsure, say N.
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index e27360652d9b..5af46442a792 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -1578,8 +1578,14 @@ static void __exit amiga_serial_remove(struct platform_device *pdev)
free_irq(IRQ_AMIGA_RBF, state);
}
-static struct platform_driver amiga_serial_driver = {
- .remove_new = __exit_p(amiga_serial_remove),
+/*
+ * amiga_serial_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver amiga_serial_driver __refdata = {
+ .remove = __exit_p(amiga_serial_remove),
.driver = {
.name = "amiga-serial",
},
@@ -1654,5 +1660,6 @@ console_initcall(amiserial_console_init);
#endif /* CONFIG_SERIAL_CONSOLE && !MODULE */
+MODULE_DESCRIPTION("Serial driver for the amiga builtin port");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:amiga-serial");
diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c
index 34421ec06a69..3a9582029005 100644
--- a/drivers/tty/goldfish.c
+++ b/drivers/tty/goldfish.c
@@ -461,7 +461,7 @@ MODULE_DEVICE_TABLE(of, goldfish_tty_of_match);
static struct platform_driver goldfish_tty_platform_driver = {
.probe = goldfish_tty_probe,
- .remove_new = goldfish_tty_remove,
+ .remove = goldfish_tty_remove,
.driver = {
.name = "goldfish_tty",
.of_match_table = goldfish_tty_of_match,
@@ -470,4 +470,5 @@ static struct platform_driver goldfish_tty_platform_driver = {
module_platform_driver(goldfish_tty_platform_driver);
+MODULE_DESCRIPTION("Goldfish TTY Driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index b1149bc62ca1..4ca7472c38e0 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -24,6 +24,7 @@
#include <linux/tty.h>
#include <linux/wait.h>
#include <net/iucv/iucv.h>
+#include <asm/machine.h>
#include "hvc_console.h"
@@ -1035,11 +1036,6 @@ static const struct attribute_group *hvc_iucv_dev_attr_groups[] = {
NULL,
};
-static void hvc_iucv_free(struct device *data)
-{
- kfree(data);
-}
-
/**
* hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
* @id: hvc_iucv_table index
@@ -1090,18 +1086,12 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
memcpy(priv->srv_name, name, 8);
ASCEBC(priv->srv_name, 8);
- /* create and setup device */
- priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL);
+ priv->dev = iucv_alloc_device(hvc_iucv_dev_attr_groups, NULL,
+ priv, "hvc_iucv%d", id);
if (!priv->dev) {
rc = -ENOMEM;
goto out_error_dev;
}
- dev_set_name(priv->dev, "hvc_iucv%d", id);
- dev_set_drvdata(priv->dev, priv);
- priv->dev->bus = &iucv_bus;
- priv->dev->parent = iucv_root;
- priv->dev->groups = hvc_iucv_dev_attr_groups;
- priv->dev->release = hvc_iucv_free;
rc = device_register(priv->dev);
if (rc) {
put_device(priv->dev);
@@ -1251,7 +1241,7 @@ static int param_set_vmidfilter(const char *val, const struct kernel_param *kp)
{
int rc;
- if (!MACHINE_IS_VM || !hvc_iucv_devices)
+ if (!machine_is_vm() || !hvc_iucv_devices)
return -ENODEV;
if (!val)
@@ -1280,7 +1270,7 @@ static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp)
size_t index, len;
void *start, *end;
- if (!MACHINE_IS_VM || !hvc_iucv_devices)
+ if (!machine_is_vm() || !hvc_iucv_devices)
return -ENODEV;
rc = 0;
@@ -1317,7 +1307,7 @@ static int __init hvc_iucv_init(void)
if (!hvc_iucv_devices)
return -ENODEV;
- if (!MACHINE_IS_VM) {
+ if (!machine_is_vm()) {
pr_notice("The z/VM IUCV HVC device driver cannot "
"be used without z/VM\n");
rc = -ENODEV;
diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c
index 095c33ad10f8..b2ec1f6efa0a 100644
--- a/drivers/tty/hvc/hvc_opal.c
+++ b/drivers/tty/hvc/hvc_opal.c
@@ -247,7 +247,7 @@ static void hvc_opal_remove(struct platform_device *dev)
static struct platform_driver hvc_opal_driver = {
.probe = hvc_opal_probe,
- .remove_new = hvc_opal_remove,
+ .remove = hvc_opal_remove,
.driver = {
.name = hvc_opal_name,
.of_match_table = hvc_opal_match,
diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c
index 0e497501f8e3..388a71afd6ef 100644
--- a/drivers/tty/hvc/hvc_xen.c
+++ b/drivers/tty/hvc/hvc_xen.c
@@ -558,7 +558,7 @@ static void xencons_backend_changed(struct xenbus_device *dev,
break;
fallthrough; /* Missed the backend's CLOSING state */
case XenbusStateClosing: {
- struct xencons_info *info = dev_get_drvdata(&dev->dev);;
+ struct xencons_info *info = dev_get_drvdata(&dev->dev);
/*
* Don't tear down the evtchn and grant ref before the other
diff --git a/drivers/tty/hvc/hvsi_lib.c b/drivers/tty/hvc/hvsi_lib.c
index 22e1bc4d8a66..b35c44caf3d7 100644
--- a/drivers/tty/hvc/hvsi_lib.c
+++ b/drivers/tty/hvc/hvsi_lib.c
@@ -303,7 +303,7 @@ int hvsilib_write_mctrl(struct hvsi_priv *pv, int dtr)
pr_devel("HVSI@%x: %s DTR...\n", pv->termno,
dtr ? "Setting" : "Clearing");
- ctrl.hdr.type = VS_CONTROL_PACKET_HEADER,
+ ctrl.hdr.type = VS_CONTROL_PACKET_HEADER;
ctrl.hdr.len = sizeof(struct hvsi_control);
ctrl.verb = cpu_to_be16(VSV_SET_MODEM_CTL);
ctrl.mask = cpu_to_be32(HVSI_TSDTR);
diff --git a/drivers/tty/ipwireless/hardware.c b/drivers/tty/ipwireless/hardware.c
index 001ec318a918..c13f52337035 100644
--- a/drivers/tty/ipwireless/hardware.c
+++ b/drivers/tty/ipwireless/hardware.c
@@ -1496,7 +1496,7 @@ exit_nomem:
static void handle_setup_get_version_rsp(struct ipw_hardware *hw,
unsigned char vers_no)
{
- del_timer(&hw->setup_timer);
+ timer_delete(&hw->setup_timer);
hw->initializing = 0;
printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": card is ready.\n");
@@ -1721,7 +1721,7 @@ void ipwireless_stop_interrupts(struct ipw_hardware *hw)
if (!hw->shutting_down) {
/* Tell everyone we are going down. */
hw->shutting_down = 1;
- del_timer(&hw->setup_timer);
+ timer_delete(&hw->setup_timer);
/* Prevent the hardware from sending any more interrupts */
do_close_hardware(hw);
diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c
index afbf7738c7c4..fa47bfcf9e86 100644
--- a/drivers/tty/mips_ejtag_fdc.c
+++ b/drivers/tty/mips_ejtag_fdc.c
@@ -1031,7 +1031,7 @@ err_stop_irq:
raw_spin_unlock_irq(&priv->lock);
} else {
priv->removing = true;
- del_timer_sync(&priv->poll_timer);
+ timer_delete_sync(&priv->poll_timer);
}
kthread_stop(priv->thread);
err_destroy_ports:
@@ -1061,7 +1061,7 @@ static int mips_ejtag_fdc_tty_cpu_down(struct mips_cdmm_device *dev)
raw_spin_unlock_irq(&priv->lock);
} else {
priv->removing = true;
- del_timer_sync(&priv->poll_timer);
+ timer_delete_sync(&priv->poll_timer);
}
kthread_stop(priv->thread);
@@ -1154,7 +1154,7 @@ static char kgdbfdc_rbuf[4];
/* write buffer to allow compaction */
static unsigned int kgdbfdc_wbuflen;
-static char kgdbfdc_wbuf[4];
+static u8 kgdbfdc_wbuf[4];
static void __iomem *kgdbfdc_setup(void)
{
@@ -1215,7 +1215,7 @@ static int kgdbfdc_read_char(void)
/* push an FDC word from write buffer to TX FIFO */
static void kgdbfdc_push_one(void)
{
- const char *bufs[1] = { kgdbfdc_wbuf };
+ const u8 *bufs[1] = { kgdbfdc_wbuf };
struct fdc_word word;
void __iomem *regs;
unsigned int i;
diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c
index ebaada8db929..329b30fac8fc 100644
--- a/drivers/tty/moxa.c
+++ b/drivers/tty/moxa.c
@@ -43,15 +43,6 @@
#include <linux/ratelimit.h>
#include <asm/io.h>
-#include <linux/uaccess.h>
-
-#define MOXA 0x400
-#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
-#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
-#define MOXA_GETDATACOUNT (MOXA + 23)
-#define MOXA_GET_IOQUEUE (MOXA + 27)
-#define MOXA_FLUSH_QUEUE (MOXA + 28)
-#define MOXA_GETMSTATUS (MOXA + 65)
/*
* System Configuration
@@ -347,8 +338,6 @@
#define MX_PARMARK 0xA0
#define MX_PARSPACE 0x20
-#define MOXA_VERSION "6.0k"
-
#define MOXA_FW_HDRLEN 32
#define MOXAMAJOR 172
@@ -357,33 +346,21 @@
#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */
#define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD)
-#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \
- (brd)->boardType == MOXA_BOARD_C320_PCI)
-
-/*
- * Define the Moxa PCI vendor and device IDs.
- */
-#define MOXA_BUS_TYPE_ISA 0
-#define MOXA_BUS_TYPE_PCI 1
+#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_PCI)
enum {
MOXA_BOARD_C218_PCI = 1,
- MOXA_BOARD_C218_ISA,
MOXA_BOARD_C320_PCI,
- MOXA_BOARD_C320_ISA,
MOXA_BOARD_CP204J,
};
static char *moxa_brdname[] =
{
"C218 Turbo PCI series",
- "C218 Turbo ISA series",
"C320 Turbo PCI series",
- "C320 Turbo ISA series",
"CP-204J series",
};
-#ifdef CONFIG_PCI
static const struct pci_device_id moxa_pcibrds[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218),
.driver_data = MOXA_BOARD_C218_PCI },
@@ -394,14 +371,12 @@ static const struct pci_device_id moxa_pcibrds[] = {
{ 0 }
};
MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
-#endif /* CONFIG_PCI */
struct moxa_port;
static struct moxa_board_conf {
int boardType;
int numPorts;
- int busType;
unsigned int ready;
@@ -413,19 +388,6 @@ static struct moxa_board_conf {
void __iomem *intTable;
} moxa_boards[MAX_BOARDS];
-struct mxser_mstatus {
- tcflag_t cflag;
- int cts;
- int dsr;
- int ri;
- int dcd;
-};
-
-struct moxaq_str {
- int inq;
- int outq;
-};
-
struct moxa_port {
struct tty_port port;
struct moxa_board_conf *board;
@@ -440,12 +402,6 @@ struct moxa_port {
u8 lowChkFlag;
};
-struct mon_str {
- int tick;
- int rxcnt[MAX_PORTS];
- int txcnt[MAX_PORTS];
-};
-
/* statusflags */
#define TXSTOPPED 1
#define LOWWAIT 2
@@ -455,17 +411,11 @@ struct mon_str {
#define WAKEUP_CHARS 256
static int ttymajor = MOXAMAJOR;
-static struct mon_str moxaLog;
static unsigned int moxaFuncTout = HZ / 2;
static unsigned int moxaLowWaterChk;
static DEFINE_MUTEX(moxa_openlock);
static DEFINE_SPINLOCK(moxa_lock);
-static unsigned long baseaddr[MAX_BOARDS];
-static unsigned int type[MAX_BOARDS];
-static unsigned int numports[MAX_BOARDS];
-static struct tty_port moxa_service_port;
-
MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
MODULE_LICENSE("GPL");
@@ -473,13 +423,6 @@ MODULE_FIRMWARE("c218tunx.cod");
MODULE_FIRMWARE("cp204unx.cod");
MODULE_FIRMWARE("c320tunx.cod");
-module_param_array(type, uint, NULL, 0);
-MODULE_PARM_DESC(type, "card type: C218=2, C320=4");
-module_param_hw_array(baseaddr, ulong, ioport, NULL, 0);
-MODULE_PARM_DESC(baseaddr, "base address");
-module_param_array(numports, uint, NULL, 0);
-MODULE_PARM_DESC(numports, "numports (ignored for C218)");
-
module_param(ttymajor, int, 0);
/*
@@ -583,104 +526,6 @@ static void moxa_low_water_check(void __iomem *ofsAddr)
* TTY operations
*/
-static int moxa_ioctl(struct tty_struct *tty,
- unsigned int cmd, unsigned long arg)
-{
- struct moxa_port *ch = tty->driver_data;
- void __user *argp = (void __user *)arg;
- int status, ret = 0;
-
- if (tty->index == MAX_PORTS) {
- if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE &&
- cmd != MOXA_GETMSTATUS)
- return -EINVAL;
- } else if (!ch)
- return -ENODEV;
-
- switch (cmd) {
- case MOXA_GETDATACOUNT:
- moxaLog.tick = jiffies;
- if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
- ret = -EFAULT;
- break;
- case MOXA_FLUSH_QUEUE:
- MoxaPortFlushData(ch, arg);
- break;
- case MOXA_GET_IOQUEUE: {
- struct moxaq_str __user *argm = argp;
- struct moxaq_str tmp;
- struct moxa_port *p;
- unsigned int i, j;
-
- for (i = 0; i < MAX_BOARDS; i++) {
- p = moxa_boards[i].ports;
- for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
- memset(&tmp, 0, sizeof(tmp));
- spin_lock_bh(&moxa_lock);
- if (moxa_boards[i].ready) {
- tmp.inq = MoxaPortRxQueue(p);
- tmp.outq = MoxaPortTxQueue(p);
- }
- spin_unlock_bh(&moxa_lock);
- if (copy_to_user(argm, &tmp, sizeof(tmp)))
- return -EFAULT;
- }
- }
- break;
- } case MOXA_GET_OQUEUE:
- status = MoxaPortTxQueue(ch);
- ret = put_user(status, (unsigned long __user *)argp);
- break;
- case MOXA_GET_IQUEUE:
- status = MoxaPortRxQueue(ch);
- ret = put_user(status, (unsigned long __user *)argp);
- break;
- case MOXA_GETMSTATUS: {
- struct mxser_mstatus __user *argm = argp;
- struct mxser_mstatus tmp;
- struct moxa_port *p;
- unsigned int i, j;
-
- for (i = 0; i < MAX_BOARDS; i++) {
- p = moxa_boards[i].ports;
- for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
- struct tty_struct *ttyp;
- memset(&tmp, 0, sizeof(tmp));
- spin_lock_bh(&moxa_lock);
- if (!moxa_boards[i].ready) {
- spin_unlock_bh(&moxa_lock);
- goto copy;
- }
-
- status = MoxaPortLineStatus(p);
- spin_unlock_bh(&moxa_lock);
-
- if (status & 1)
- tmp.cts = 1;
- if (status & 2)
- tmp.dsr = 1;
- if (status & 4)
- tmp.dcd = 1;
-
- ttyp = tty_port_tty_get(&p->port);
- if (!ttyp)
- tmp.cflag = p->cflag;
- else
- tmp.cflag = ttyp->termios.c_cflag;
- tty_kref_put(ttyp);
-copy:
- if (copy_to_user(argm, &tmp, sizeof(tmp)))
- return -EFAULT;
- }
- }
- break;
- }
- default:
- ret = -ENOIOCTLCMD;
- }
- return ret;
-}
-
static int moxa_break_ctl(struct tty_struct *tty, int state)
{
struct moxa_port *port = tty->driver_data;
@@ -697,7 +542,6 @@ static const struct tty_operations moxa_ops = {
.write_room = moxa_write_room,
.flush_buffer = moxa_flush_buffer,
.chars_in_buffer = moxa_chars_in_buffer,
- .ioctl = moxa_ioctl,
.set_termios = moxa_set_termios,
.stop = moxa_stop,
.start = moxa_start,
@@ -725,7 +569,6 @@ static DEFINE_TIMER(moxaTimer, moxa_poll);
static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
{
switch (brd->boardType) {
- case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
if (model != 1)
goto err;
@@ -769,7 +612,6 @@ static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
msleep(2000);
switch (brd->boardType) {
- case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
tmp = readw(baseAddr + C218_key);
if (tmp != C218_KeyCode)
@@ -833,7 +675,6 @@ static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
switch (brd->boardType) {
case MOXA_BOARD_CP204J:
- case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
key = C218_key;
loadbuf = C218_LoadBuf;
@@ -898,15 +739,9 @@ static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
return -EIO;
if (MOXA_IS_320(brd)) {
- if (brd->busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */
- writew(0x3800, baseAddr + TMS320_PORT1);
- writew(0x3900, baseAddr + TMS320_PORT2);
- writew(28499, baseAddr + TMS320_CLOCK);
- } else {
- writew(0x3200, baseAddr + TMS320_PORT1);
- writew(0x3400, baseAddr + TMS320_PORT2);
- writew(19999, baseAddr + TMS320_CLOCK);
- }
+ writew(0x3800, baseAddr + TMS320_PORT1);
+ writew(0x3900, baseAddr + TMS320_PORT2);
+ writew(28499, baseAddr + TMS320_CLOCK);
}
writew(1, baseAddr + Disable_IRQ);
writew(0, baseAddr + Magic_no);
@@ -957,7 +792,6 @@ static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
return retval;
switch (brd->boardType) {
- case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
case MOXA_BOARD_CP204J:
port = brd->ports;
@@ -1141,7 +975,6 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
}
switch (brd->boardType) {
- case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
file = "c218tunx.cod";
break;
@@ -1227,7 +1060,6 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
kfree(brd->ports);
}
-#ifdef CONFIG_PCI
static int moxa_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -1270,7 +1102,6 @@ static int moxa_pci_probe(struct pci_dev *pdev,
board->boardType = board_type;
switch (board_type) {
- case MOXA_BOARD_C218_ISA:
case MOXA_BOARD_C218_PCI:
board->numPorts = 8;
break;
@@ -1282,7 +1113,6 @@ static int moxa_pci_probe(struct pci_dev *pdev,
board->numPorts = 0;
break;
}
- board->busType = MOXA_BUS_TYPE_PCI;
retval = moxa_init_board(board, &pdev->dev);
if (retval)
@@ -1318,21 +1148,12 @@ static struct pci_driver moxa_pci_driver = {
.probe = moxa_pci_probe,
.remove = moxa_pci_remove
};
-#endif /* CONFIG_PCI */
static int __init moxa_init(void)
{
- unsigned int isabrds = 0;
int retval = 0;
- struct moxa_board_conf *brd = moxa_boards;
- unsigned int i;
-
- printk(KERN_INFO "MOXA Intellio family driver version %s\n",
- MOXA_VERSION);
- tty_port_init(&moxa_service_port);
-
- moxaDriver = tty_alloc_driver(MAX_PORTS + 1,
+ moxaDriver = tty_alloc_driver(MAX_PORTS,
TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV);
if (IS_ERR(moxaDriver))
@@ -1348,8 +1169,6 @@ static int __init moxa_init(void)
moxaDriver->init_termios.c_ispeed = 9600;
moxaDriver->init_termios.c_ospeed = 9600;
tty_set_operations(moxaDriver, &moxa_ops);
- /* Having one more port only for ioctls is ugly */
- tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS);
if (tty_register_driver(moxaDriver)) {
printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
@@ -1357,66 +1176,18 @@ static int __init moxa_init(void)
return -1;
}
- /* Find the boards defined from module args. */
-
- for (i = 0; i < MAX_BOARDS; i++) {
- if (!baseaddr[i])
- break;
- if (type[i] == MOXA_BOARD_C218_ISA ||
- type[i] == MOXA_BOARD_C320_ISA) {
- pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
- isabrds + 1, moxa_brdname[type[i] - 1],
- baseaddr[i]);
- brd->boardType = type[i];
- brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
- numports[i];
- brd->busType = MOXA_BUS_TYPE_ISA;
- brd->basemem = ioremap(baseaddr[i], 0x4000);
- if (!brd->basemem) {
- printk(KERN_ERR "MOXA: can't remap %lx\n",
- baseaddr[i]);
- continue;
- }
- if (moxa_init_board(brd, NULL)) {
- iounmap(brd->basemem);
- brd->basemem = NULL;
- continue;
- }
-
- printk(KERN_INFO "MOXA isa board found at 0x%.8lx and "
- "ready (%u ports, firmware loaded)\n",
- baseaddr[i], brd->numPorts);
-
- brd++;
- isabrds++;
- }
- }
-
-#ifdef CONFIG_PCI
retval = pci_register_driver(&moxa_pci_driver);
- if (retval) {
+ if (retval)
printk(KERN_ERR "Can't register MOXA pci driver!\n");
- if (isabrds)
- retval = 0;
- }
-#endif
return retval;
}
static void __exit moxa_exit(void)
{
- unsigned int i;
-
-#ifdef CONFIG_PCI
pci_unregister_driver(&moxa_pci_driver);
-#endif
-
- for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
- if (moxa_boards[i].ready)
- moxa_board_deinit(&moxa_boards[i]);
- del_timer_sync(&moxaTimer);
+ timer_delete_sync(&moxaTimer);
tty_unregister_driver(moxaDriver);
tty_driver_kref_put(moxaDriver);
@@ -1457,9 +1228,6 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
int port;
port = tty->index;
- if (port == MAX_PORTS) {
- return capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
- }
if (mutex_lock_interruptible(&moxa_openlock))
return -ERESTARTSYS;
brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
@@ -2182,7 +1950,6 @@ static ssize_t MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer,
c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
if (c > len)
c = len;
- moxaLog.txcnt[port->port.tty->index] += c;
total = c;
if (spage == epage) {
bufhead = readw(ofsAddr + Ofs_txb);
@@ -2224,7 +1991,6 @@ static ssize_t MoxaPortWriteData(struct tty_struct *tty, const u8 *buffer,
static int MoxaPortReadData(struct moxa_port *port)
{
- struct tty_struct *tty = port->port.tty;
void __iomem *baseAddr, *ofsAddr, *ofs;
u8 *dst;
unsigned int count, len, total;
@@ -2243,7 +2009,6 @@ static int MoxaPortReadData(struct moxa_port *port)
return 0;
total = count;
- moxaLog.rxcnt[tty->index] += total;
if (spage == epage) {
bufhead = readw(ofsAddr + Ofs_rxb);
writew(spage, baseAddr + Control_reg);
@@ -2331,8 +2096,6 @@ static int moxa_get_serial_info(struct tty_struct *tty,
{
struct moxa_port *info = tty->driver_data;
- if (tty->index == MAX_PORTS)
- return -EINVAL;
if (!info)
return -ENODEV;
mutex_lock(&info->port.mutex);
@@ -2352,8 +2115,6 @@ static int moxa_set_serial_info(struct tty_struct *tty,
struct moxa_port *info = tty->driver_data;
unsigned int close_delay;
- if (tty->index == MAX_PORTS)
- return -EINVAL;
if (!info)
return -ENODEV;
diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c
index 458bb1280ebf..4d45eca4929a 100644
--- a/drivers/tty/mxser.c
+++ b/drivers/tty/mxser.c
@@ -208,9 +208,6 @@ static const struct {
};
#define UART_INFO_NUM ARRAY_SIZE(Gpci_uart_info)
-
-/* driver_data correspond to the lines in the structure above
- see also ISA probe function before you change something */
static const struct pci_device_id mxser_pcibrds[] = {
{ PCI_DEVICE_DATA(MOXA, C168, 8) },
{ PCI_DEVICE_DATA(MOXA, C104, 4) },
@@ -288,7 +285,7 @@ struct mxser_board {
enum mxser_must_hwid must_hwid;
speed_t max_baud;
- struct mxser_port ports[] __counted_by(nports);
+ struct mxser_port ports[] /* __counted_by(nports) */;
};
static DECLARE_BITMAP(mxser_boards, MXSER_BOARDS);
@@ -986,7 +983,7 @@ static int mxser_get_serial_info(struct tty_struct *tty,
ss->baud_base = MXSER_BAUD_BASE;
ss->close_delay = close_delay;
ss->closing_wait = closing_wait;
- ss->custom_divisor = MXSER_CUSTOM_DIVISOR,
+ ss->custom_divisor = MXSER_CUSTOM_DIVISOR;
mutex_unlock(&port->mutex);
return 0;
}
@@ -1773,8 +1770,6 @@ static void mxser_initbrd(struct mxser_board *brd, bool high_baud)
mxser_process_txrx_fifo(info);
- info->port.close_delay = 5 * HZ / 10;
- info->port.closing_wait = 30 * HZ;
spin_lock_init(&info->slock);
/* before set INT ISR, disable all int */
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 4036566febcb..40a336ef8c7e 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -245,16 +245,18 @@ enum gsm_encoding {
enum gsm_mux_state {
GSM_SEARCH,
- GSM_START,
- GSM_ADDRESS,
- GSM_CONTROL,
- GSM_LEN,
- GSM_DATA,
- GSM_FCS,
- GSM_OVERRUN,
- GSM_LEN0,
- GSM_LEN1,
- GSM_SSOF,
+ GSM0_ADDRESS,
+ GSM0_CONTROL,
+ GSM0_LEN0,
+ GSM0_LEN1,
+ GSM0_DATA,
+ GSM0_FCS,
+ GSM0_SSOF,
+ GSM1_START,
+ GSM1_ADDRESS,
+ GSM1_CONTROL,
+ GSM1_DATA,
+ GSM1_OVERRUN,
};
/*
@@ -1939,7 +1941,7 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
/* Does the reply match our command */
if (ctrl != NULL && (command == ctrl->cmd || command == CMD_NSC)) {
/* Our command was replied to, kill the retry timer */
- del_timer(&gsm->t2_timer);
+ timer_delete(&gsm->t2_timer);
gsm->pending_cmd = NULL;
/* Rejected by the other end */
if (command == CMD_NSC)
@@ -2129,7 +2131,7 @@ static int gsm_control_wait(struct gsm_mux *gsm, struct gsm_control *control)
static void gsm_dlci_close(struct gsm_dlci *dlci)
{
- del_timer(&dlci->t1);
+ timer_delete(&dlci->t1);
if (debug & DBG_ERRORS)
pr_debug("DLCI %d goes closed.\n", dlci->addr);
dlci->state = DLCI_CLOSED;
@@ -2142,7 +2144,7 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
tty_port_set_initialized(&dlci->port, false);
wake_up_interruptible(&dlci->port.open_wait);
} else {
- del_timer(&dlci->gsm->ka_timer);
+ timer_delete(&dlci->gsm->ka_timer);
dlci->gsm->dead = true;
}
/* A DLCI 0 close is a MUX termination so we need to kick that
@@ -2164,7 +2166,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
/* Note that SABM UA .. SABM UA first UA lost can mean that we go
open -> open */
- del_timer(&dlci->t1);
+ timer_delete(&dlci->t1);
/* This will let a tty open continue */
dlci->state = DLCI_OPEN;
dlci->constipated = false;
@@ -2222,7 +2224,7 @@ static int gsm_dlci_negotiate(struct gsm_dlci *dlci)
*
* Some control dlci can stay in ADM mode with other dlci working just
* fine. In that case we can just keep the control dlci open after the
- * DLCI_OPENING retries time out.
+ * DLCI_OPENING receives DM.
*/
static void gsm_dlci_t1(struct timer_list *t)
@@ -2241,16 +2243,19 @@ static void gsm_dlci_t1(struct timer_list *t)
}
break;
case DLCI_OPENING:
- if (dlci->retries) {
- dlci->retries--;
- gsm_command(dlci->gsm, dlci->addr, SABM|PF);
- mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
- } else if (!dlci->addr && gsm->control == (DM | PF)) {
+ if (!dlci->addr && gsm->control == (DM | PF)) {
if (debug & DBG_ERRORS)
- pr_info("DLCI %d opening in ADM mode.\n",
- dlci->addr);
+ pr_info("DLCI 0 opening in ADM mode.\n");
dlci->mode = DLCI_MODE_ADM;
gsm_dlci_open(dlci);
+ } else if (dlci->retries) {
+ if (!dlci->addr || !gsm->dlci[0] ||
+ gsm->dlci[0]->state != DLCI_OPENING) {
+ dlci->retries--;
+ gsm_command(dlci->gsm, dlci->addr, SABM|PF);
+ }
+
+ mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
} else {
gsm->open_error++;
gsm_dlci_begin_close(dlci); /* prevent half open link */
@@ -2306,7 +2311,9 @@ static void gsm_dlci_begin_open(struct gsm_dlci *dlci)
dlci->retries = gsm->n2;
if (!need_pn) {
dlci->state = DLCI_OPENING;
- gsm_command(gsm, dlci->addr, SABM|PF);
+ if (!dlci->addr || !gsm->dlci[0] ||
+ gsm->dlci[0]->state != DLCI_OPENING)
+ gsm_command(gsm, dlci->addr, SABM|PF);
} else {
/* Configure DLCI before setup */
dlci->state = DLCI_CONFIGURE;
@@ -2847,6 +2854,30 @@ invalid:
return;
}
+/**
+ * gsm0_receive_state_check_and_fix - check and correct receive state
+ * @gsm: gsm data for this ldisc instance
+ *
+ * Ensures that the current receive state is valid for basic option mode.
+ */
+
+static void gsm0_receive_state_check_and_fix(struct gsm_mux *gsm)
+{
+ switch (gsm->state) {
+ case GSM_SEARCH:
+ case GSM0_ADDRESS:
+ case GSM0_CONTROL:
+ case GSM0_LEN0:
+ case GSM0_LEN1:
+ case GSM0_DATA:
+ case GSM0_FCS:
+ case GSM0_SSOF:
+ break;
+ default:
+ gsm->state = GSM_SEARCH;
+ break;
+ }
+}
/**
* gsm0_receive - perform processing for non-transparency
@@ -2860,26 +2891,27 @@ static void gsm0_receive(struct gsm_mux *gsm, u8 c)
{
unsigned int len;
+ gsm0_receive_state_check_and_fix(gsm);
switch (gsm->state) {
case GSM_SEARCH: /* SOF marker */
if (c == GSM0_SOF) {
- gsm->state = GSM_ADDRESS;
+ gsm->state = GSM0_ADDRESS;
gsm->address = 0;
gsm->len = 0;
gsm->fcs = INIT_FCS;
}
break;
- case GSM_ADDRESS: /* Address EA */
+ case GSM0_ADDRESS: /* Address EA */
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
if (gsm_read_ea(&gsm->address, c))
- gsm->state = GSM_CONTROL;
+ gsm->state = GSM0_CONTROL;
break;
- case GSM_CONTROL: /* Control Byte */
+ case GSM0_CONTROL: /* Control Byte */
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
gsm->control = c;
- gsm->state = GSM_LEN0;
+ gsm->state = GSM0_LEN0;
break;
- case GSM_LEN0: /* Length EA */
+ case GSM0_LEN0: /* Length EA */
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
if (gsm_read_ea(&gsm->len, c)) {
if (gsm->len > gsm->mru) {
@@ -2889,14 +2921,14 @@ static void gsm0_receive(struct gsm_mux *gsm, u8 c)
}
gsm->count = 0;
if (!gsm->len)
- gsm->state = GSM_FCS;
+ gsm->state = GSM0_FCS;
else
- gsm->state = GSM_DATA;
+ gsm->state = GSM0_DATA;
break;
}
- gsm->state = GSM_LEN1;
+ gsm->state = GSM0_LEN1;
break;
- case GSM_LEN1:
+ case GSM0_LEN1:
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
len = c;
gsm->len |= len << 7;
@@ -2907,26 +2939,29 @@ static void gsm0_receive(struct gsm_mux *gsm, u8 c)
}
gsm->count = 0;
if (!gsm->len)
- gsm->state = GSM_FCS;
+ gsm->state = GSM0_FCS;
else
- gsm->state = GSM_DATA;
+ gsm->state = GSM0_DATA;
break;
- case GSM_DATA: /* Data */
+ case GSM0_DATA: /* Data */
gsm->buf[gsm->count++] = c;
- if (gsm->count == gsm->len) {
+ if (gsm->count >= MAX_MRU) {
+ gsm->bad_size++;
+ gsm->state = GSM_SEARCH;
+ } else if (gsm->count >= gsm->len) {
/* Calculate final FCS for UI frames over all data */
if ((gsm->control & ~PF) != UIH) {
gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf,
gsm->count);
}
- gsm->state = GSM_FCS;
+ gsm->state = GSM0_FCS;
}
break;
- case GSM_FCS: /* FCS follows the packet */
+ case GSM0_FCS: /* FCS follows the packet */
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
- gsm->state = GSM_SSOF;
+ gsm->state = GSM0_SSOF;
break;
- case GSM_SSOF:
+ case GSM0_SSOF:
gsm->state = GSM_SEARCH;
if (c == GSM0_SOF)
gsm_queue(gsm);
@@ -2940,6 +2975,29 @@ static void gsm0_receive(struct gsm_mux *gsm, u8 c)
}
/**
+ * gsm1_receive_state_check_and_fix - check and correct receive state
+ * @gsm: gsm data for this ldisc instance
+ *
+ * Ensures that the current receive state is valid for advanced option mode.
+ */
+
+static void gsm1_receive_state_check_and_fix(struct gsm_mux *gsm)
+{
+ switch (gsm->state) {
+ case GSM_SEARCH:
+ case GSM1_START:
+ case GSM1_ADDRESS:
+ case GSM1_CONTROL:
+ case GSM1_DATA:
+ case GSM1_OVERRUN:
+ break;
+ default:
+ gsm->state = GSM_SEARCH;
+ break;
+ }
+}
+
+/**
* gsm1_receive - perform processing for non-transparency
* @gsm: gsm data for this ldisc instance
* @c: character
@@ -2949,6 +3007,7 @@ static void gsm0_receive(struct gsm_mux *gsm, u8 c)
static void gsm1_receive(struct gsm_mux *gsm, u8 c)
{
+ gsm1_receive_state_check_and_fix(gsm);
/* handle XON/XOFF */
if ((c & ISO_IEC_646_MASK) == XON) {
gsm->constipated = true;
@@ -2961,11 +3020,11 @@ static void gsm1_receive(struct gsm_mux *gsm, u8 c)
}
if (c == GSM1_SOF) {
/* EOF is only valid in frame if we have got to the data state */
- if (gsm->state == GSM_DATA) {
+ if (gsm->state == GSM1_DATA) {
if (gsm->count < 1) {
/* Missing FSC */
gsm->malformed++;
- gsm->state = GSM_START;
+ gsm->state = GSM1_START;
return;
}
/* Remove the FCS from data */
@@ -2981,14 +3040,14 @@ static void gsm1_receive(struct gsm_mux *gsm, u8 c)
gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->buf[gsm->count]);
gsm->len = gsm->count;
gsm_queue(gsm);
- gsm->state = GSM_START;
+ gsm->state = GSM1_START;
return;
}
/* Any partial frame was a runt so go back to start */
- if (gsm->state != GSM_START) {
+ if (gsm->state != GSM1_START) {
if (gsm->state != GSM_SEARCH)
gsm->malformed++;
- gsm->state = GSM_START;
+ gsm->state = GSM1_START;
}
/* A SOF in GSM_START means we are still reading idling or
framing bytes */
@@ -3009,30 +3068,30 @@ static void gsm1_receive(struct gsm_mux *gsm, u8 c)
gsm->escape = false;
}
switch (gsm->state) {
- case GSM_START: /* First byte after SOF */
+ case GSM1_START: /* First byte after SOF */
gsm->address = 0;
- gsm->state = GSM_ADDRESS;
+ gsm->state = GSM1_ADDRESS;
gsm->fcs = INIT_FCS;
fallthrough;
- case GSM_ADDRESS: /* Address continuation */
+ case GSM1_ADDRESS: /* Address continuation */
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
if (gsm_read_ea(&gsm->address, c))
- gsm->state = GSM_CONTROL;
+ gsm->state = GSM1_CONTROL;
break;
- case GSM_CONTROL: /* Control Byte */
+ case GSM1_CONTROL: /* Control Byte */
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
gsm->control = c;
gsm->count = 0;
- gsm->state = GSM_DATA;
+ gsm->state = GSM1_DATA;
break;
- case GSM_DATA: /* Data */
- if (gsm->count > gsm->mru) { /* Allow one for the FCS */
- gsm->state = GSM_OVERRUN;
+ case GSM1_DATA: /* Data */
+ if (gsm->count > gsm->mru || gsm->count > MAX_MRU) { /* Allow one for the FCS */
+ gsm->state = GSM1_OVERRUN;
gsm->bad_size++;
} else
gsm->buf[gsm->count++] = c;
break;
- case GSM_OVERRUN: /* Over-long - eg a dropped SOF */
+ case GSM1_OVERRUN: /* Over-long - eg a dropped SOF */
break;
default:
pr_debug("%s: unhandled state: %d\n", __func__, gsm->state);
@@ -3085,9 +3144,9 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
}
/* Finish outstanding timers, making sure they are done */
- del_timer_sync(&gsm->kick_timer);
- del_timer_sync(&gsm->t2_timer);
- del_timer_sync(&gsm->ka_timer);
+ timer_delete_sync(&gsm->kick_timer);
+ timer_delete_sync(&gsm->t2_timer);
+ timer_delete_sync(&gsm->ka_timer);
/* Finish writing to ldisc */
flush_work(&gsm->tx_work);
@@ -3103,6 +3162,8 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc)
mutex_unlock(&gsm->mutex);
/* Now wipe the queues */
tty_ldisc_flush(gsm->tty);
+
+ guard(spinlock_irqsave)(&gsm->tx_lock);
list_for_each_entry_safe(txq, ntxq, &gsm->tx_ctrl_list, list)
kfree(txq);
INIT_LIST_HEAD(&gsm->tx_ctrl_list);
@@ -4010,7 +4071,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
mux_net = netdev_priv(net);
mux_net->dlci = dlci;
kref_init(&mux_net->ref);
- strncpy(nc->if_name, net->name, IFNAMSIZ); /* return net name */
+ strscpy(nc->if_name, net->name); /* return net name */
/* reconfigure dlci for network */
dlci->prev_adaption = dlci->adaption;
@@ -4195,7 +4256,7 @@ static const struct tty_port_operations gsm_port_ops = {
static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
{
struct gsm_mux *gsm;
- struct gsm_dlci *dlci;
+ struct gsm_dlci *dlci, *dlci0;
unsigned int line = tty->index;
unsigned int mux = mux_line_to_num(line);
bool alloc = false;
@@ -4218,10 +4279,20 @@ static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
perspective as we don't have to worry about this
if DLCI0 is lost */
mutex_lock(&gsm->mutex);
- if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) {
+
+ dlci0 = gsm->dlci[0];
+ if (dlci0 && dlci0->state != DLCI_OPEN) {
mutex_unlock(&gsm->mutex);
- return -EL2NSYNC;
+
+ if (dlci0->state == DLCI_OPENING)
+ wait_event(gsm->event, dlci0->state != DLCI_OPENING);
+
+ if (dlci0->state != DLCI_OPEN)
+ return -EL2NSYNC;
+
+ mutex_lock(&gsm->mutex);
}
+
dlci = gsm->dlci[line];
if (dlci == NULL) {
alloc = true;
@@ -4580,5 +4651,6 @@ module_init(gsm_init);
module_exit(gsm_exit);
+MODULE_DESCRIPTION("GSM 0710 tty multiplexor");
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_GSM0710);
diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
index 1615f074ab86..4a4dc58b866a 100644
--- a/drivers/tty/n_hdlc.c
+++ b/drivers/tty/n_hdlc.c
@@ -822,6 +822,7 @@ static void __exit n_hdlc_exit(void)
module_init(n_hdlc_init);
module_exit(n_hdlc_exit);
+MODULE_DESCRIPTION("HDLC line discipline support");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
module_param(maxframe, int, 0);
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index f252d0b5a434..6af3f3a0b531 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -56,6 +56,8 @@
*/
#define WAKEUP_CHARS 256
+#define N_TTY_BUF_SIZE 4096
+
/*
* This defines the low- and high-watermarks for throttling and
* unthrottling the TTY driver. These watermarks are used for
@@ -79,14 +81,6 @@
#define ECHO_BLOCK 256
#define ECHO_DISCARD_WATERMARK N_TTY_BUF_SIZE - (ECHO_BLOCK + 32)
-
-#undef N_TTY_TRACE
-#ifdef N_TTY_TRACE
-# define n_tty_trace(f, args...) trace_printk(f, ##args)
-#else
-# define n_tty_trace(f, args...) no_printk(f, ##args)
-#endif
-
struct n_tty_data {
/* producer-published */
size_t read_head;
@@ -486,18 +480,13 @@ static int do_output_char(u8 c, struct tty_struct *tty, int space)
static int process_output(u8 c, struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
- int space, retval;
- mutex_lock(&ldata->output_lock);
-
- space = tty_write_room(tty);
- retval = do_output_char(c, tty, space);
+ guard(mutex)(&ldata->output_lock);
- mutex_unlock(&ldata->output_lock);
- if (retval < 0)
+ if (do_output_char(c, tty, tty_write_room(tty)) < 0)
return -1;
- else
- return 0;
+
+ return 0;
}
/**
@@ -522,17 +511,15 @@ static ssize_t process_output_block(struct tty_struct *tty,
const u8 *buf, unsigned int nr)
{
struct n_tty_data *ldata = tty->disc_data;
- int space;
- int i;
+ unsigned int space, i;
const u8 *cp;
- mutex_lock(&ldata->output_lock);
+ guard(mutex)(&ldata->output_lock);
space = tty_write_room(tty);
- if (space <= 0) {
- mutex_unlock(&ldata->output_lock);
- return space;
- }
+ if (space == 0)
+ return 0;
+
if (nr > space)
nr = space;
@@ -544,18 +531,18 @@ static ssize_t process_output_block(struct tty_struct *tty,
if (O_ONLRET(tty))
ldata->column = 0;
if (O_ONLCR(tty))
- goto break_out;
+ goto do_write;
ldata->canon_column = ldata->column;
break;
case '\r':
if (O_ONOCR(tty) && ldata->column == 0)
- goto break_out;
+ goto do_write;
if (O_OCRNL(tty))
- goto break_out;
+ goto do_write;
ldata->canon_column = ldata->column = 0;
break;
case '\t':
- goto break_out;
+ goto do_write;
case '\b':
if (ldata->column > 0)
ldata->column--;
@@ -563,18 +550,15 @@ static ssize_t process_output_block(struct tty_struct *tty,
default:
if (!iscntrl(c)) {
if (O_OLCUC(tty))
- goto break_out;
+ goto do_write;
if (!is_continuation(c, tty))
ldata->column++;
}
break;
}
}
-break_out:
- i = tty->ops->write(tty, buf, i);
-
- mutex_unlock(&ldata->output_lock);
- return i;
+do_write:
+ return tty->ops->write(tty, buf, i);
}
static int n_tty_process_echo_ops(struct tty_struct *tty, size_t *tail,
@@ -696,7 +680,7 @@ static int n_tty_process_echo_ops(struct tty_struct *tty, size_t *tail,
static size_t __process_echoes(struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
- int space, old_space;
+ unsigned int space, old_space;
size_t tail;
u8 c;
@@ -1619,15 +1603,25 @@ static void __receive_buf(struct tty_struct *tty, const u8 *cp, const u8 *fp,
else if (ldata->raw || (L_EXTPROC(tty) && !preops))
n_tty_receive_buf_raw(tty, cp, fp, count);
else if (tty->closing && !L_EXTPROC(tty)) {
- if (la_count > 0)
+ if (la_count > 0) {
n_tty_receive_buf_closing(tty, cp, fp, la_count, true);
- if (count > la_count)
- n_tty_receive_buf_closing(tty, cp, fp, count - la_count, false);
+ cp += la_count;
+ if (fp)
+ fp += la_count;
+ count -= la_count;
+ }
+ if (count > 0)
+ n_tty_receive_buf_closing(tty, cp, fp, count, false);
} else {
- if (la_count > 0)
+ if (la_count > 0) {
n_tty_receive_buf_standard(tty, cp, fp, la_count, true);
- if (count > la_count)
- n_tty_receive_buf_standard(tty, cp, fp, count - la_count, false);
+ cp += la_count;
+ if (fp)
+ fp += la_count;
+ count -= la_count;
+ }
+ if (count > 0)
+ n_tty_receive_buf_standard(tty, cp, fp, count, false);
flush_echoes(tty);
if (tty->ops->flush_chars)
@@ -2024,9 +2018,6 @@ static bool canon_copy_from_read_buf(const struct tty_struct *tty, u8 **kbp,
tail = MASK(ldata->read_tail);
size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
- n_tty_trace("%s: nr:%zu tail:%zu n:%zu size:%zu\n",
- __func__, *nr, tail, n, size);
-
eol = find_next_bit(ldata->read_flags, size, tail);
more = n - (size - tail);
if (eol == N_TTY_BUF_SIZE && more) {
@@ -2044,9 +2035,6 @@ static bool canon_copy_from_read_buf(const struct tty_struct *tty, u8 **kbp,
if (!found || read_buf(ldata, eol) != __DISABLED_CHAR)
n = c;
- n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n",
- __func__, eol, found, n, c, tail, more);
-
tty_copy(tty, *kbp, tail, n);
*kbp += n;
*nr -= n;
@@ -2123,6 +2111,66 @@ static int job_control(struct tty_struct *tty, struct file *file)
return __tty_check_change(tty, SIGTTIN);
}
+/*
+ * We still hold the atomic_read_lock and the termios_rwsem, and can just
+ * continue to copy data.
+ */
+static ssize_t n_tty_continue_cookie(struct tty_struct *tty, u8 *kbuf,
+ size_t nr, void **cookie)
+{
+ struct n_tty_data *ldata = tty->disc_data;
+ u8 *kb = kbuf;
+
+ if (ldata->icanon && !L_EXTPROC(tty)) {
+ /*
+ * If we have filled the user buffer, see if we should skip an
+ * EOF character before releasing the lock and returning done.
+ */
+ if (!nr)
+ canon_skip_eof(ldata);
+ else if (canon_copy_from_read_buf(tty, &kb, &nr))
+ return kb - kbuf;
+ } else {
+ if (copy_from_read_buf(tty, &kb, &nr))
+ return kb - kbuf;
+ }
+
+ /* No more data - release locks and stop retries */
+ n_tty_kick_worker(tty);
+ n_tty_check_unthrottle(tty);
+ up_read(&tty->termios_rwsem);
+ mutex_unlock(&ldata->atomic_read_lock);
+ *cookie = NULL;
+
+ return kb - kbuf;
+}
+
+static int n_tty_wait_for_input(struct tty_struct *tty, struct file *file,
+ struct wait_queue_entry *wait, long *timeout)
+{
+ if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+ return -EIO;
+ if (tty_hung_up_p(file))
+ return 0;
+ /*
+ * Abort readers for ttys which never actually get hung up.
+ * See __tty_hangup().
+ */
+ if (test_bit(TTY_HUPPING, &tty->flags))
+ return 0;
+ if (!*timeout)
+ return 0;
+ if (tty_io_nonblock(tty, file))
+ return -EAGAIN;
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ up_read(&tty->termios_rwsem);
+ *timeout = wait_woken(wait, TASK_INTERRUPTIBLE, *timeout);
+ down_read(&tty->termios_rwsem);
+
+ return 1;
+}
/**
* n_tty_read - read function for tty
@@ -2156,36 +2204,9 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf,
bool packet;
size_t old_tail;
- /*
- * Is this a continuation of a read started earler?
- *
- * If so, we still hold the atomic_read_lock and the
- * termios_rwsem, and can just continue to copy data.
- */
- if (*cookie) {
- if (ldata->icanon && !L_EXTPROC(tty)) {
- /*
- * If we have filled the user buffer, see
- * if we should skip an EOF character before
- * releasing the lock and returning done.
- */
- if (!nr)
- canon_skip_eof(ldata);
- else if (canon_copy_from_read_buf(tty, &kb, &nr))
- return kb - kbuf;
- } else {
- if (copy_from_read_buf(tty, &kb, &nr))
- return kb - kbuf;
- }
-
- /* No more data - release locks and stop retries */
- n_tty_kick_worker(tty);
- n_tty_check_unthrottle(tty);
- up_read(&tty->termios_rwsem);
- mutex_unlock(&ldata->atomic_read_lock);
- *cookie = NULL;
- return kb - kbuf;
- }
+ /* Is this a continuation of a read started earlier? */
+ if (*cookie)
+ return n_tty_continue_cookie(tty, kbuf, nr, cookie);
retval = job_control(tty, file);
if (retval < 0)
@@ -2240,34 +2261,12 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf,
tty_buffer_flush_work(tty->port);
down_read(&tty->termios_rwsem);
if (!input_available_p(tty, 0)) {
- if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
- retval = -EIO;
- break;
- }
- if (tty_hung_up_p(file))
- break;
- /*
- * Abort readers for ttys which never actually
- * get hung up. See __tty_hangup().
- */
- if (test_bit(TTY_HUPPING, &tty->flags))
- break;
- if (!timeout)
- break;
- if (tty_io_nonblock(tty, file)) {
- retval = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
+ int ret = n_tty_wait_for_input(tty, file, &wait,
+ &timeout);
+ if (ret <= 0) {
+ retval = ret;
break;
}
- up_read(&tty->termios_rwsem);
-
- timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
- timeout);
-
- down_read(&tty->termios_rwsem);
continue;
}
}
@@ -2282,21 +2281,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, u8 *kbuf,
nr--;
}
- /*
- * Copy data, and if there is more to be had
- * and we have nothing more to wait for, then
- * let's mark us for retries.
- *
- * NOTE! We return here with both the termios_sem
- * and atomic_read_lock still held, the retries
- * will release them when done.
- */
- if (copy_from_read_buf(tty, &kb, &nr) && kb - kbuf >= minimum) {
-more_to_be_read:
- remove_wait_queue(&tty->read_wait, &wait);
- *cookie = cookie;
- return kb - kbuf;
- }
+ if (copy_from_read_buf(tty, &kb, &nr) && kb - kbuf >= minimum)
+ goto more_to_be_read;
}
n_tty_check_unthrottle(tty);
@@ -2323,6 +2309,18 @@ more_to_be_read:
retval = kb - kbuf;
return retval;
+more_to_be_read:
+ /*
+ * There is more to be had and we have nothing more to wait for, so
+ * let's mark us for retries.
+ *
+ * NOTE! We return here with both the termios_sem and atomic_read_lock
+ * still held, the retries will release them when done.
+ */
+ remove_wait_queue(&tty->read_wait, &wait);
+ *cookie = cookie;
+
+ return kb - kbuf;
}
/**
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index df08f13052ff..8bb1a01fef2a 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -798,7 +798,7 @@ static int ptmx_open(struct inode *inode, struct file *filp)
nonseekable_open(inode, filp);
/* We refuse fsnotify events on ptmx, since it's a shared resource */
- filp->f_mode |= FMODE_NONOTIFY;
+ file_set_fsnotify_mode(filp, FMODE_NONOTIFY);
retval = tty_alloc_file(filp);
if (retval)
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index 613cb356b918..eb2a2e58fe78 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -85,7 +85,7 @@ static const struct device_type serdev_ctrl_type = {
.release = serdev_ctrl_release,
};
-static int serdev_device_match(struct device *dev, struct device_driver *drv)
+static int serdev_device_match(struct device *dev, const struct device_driver *drv)
{
if (!is_serdev_device(dev))
return 0;
@@ -316,17 +316,6 @@ void serdev_device_write_flush(struct serdev_device *serdev)
}
EXPORT_SYMBOL_GPL(serdev_device_write_flush);
-int serdev_device_write_room(struct serdev_device *serdev)
-{
- struct serdev_controller *ctrl = serdev->ctrl;
-
- if (!ctrl || !ctrl->ops->write_room)
- return 0;
-
- return serdev->ctrl->ops->write_room(ctrl);
-}
-EXPORT_SYMBOL_GPL(serdev_device_write_room);
-
unsigned int serdev_device_set_baudrate(struct serdev_device *serdev, unsigned int speed)
{
struct serdev_controller *ctrl = serdev->ctrl;
@@ -529,7 +518,7 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl)
bool found = false;
for_each_available_child_of_node(ctrl->dev.of_node, node) {
- if (!of_get_property(node, "compatible", NULL))
+ if (!of_property_present(node, "compatible"))
continue;
dev_dbg(&ctrl->dev, "adding child %pOF\n", node);
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index 3d7ae7fa5018..bab1b143b8a6 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -92,14 +92,6 @@ static void ttyport_write_flush(struct serdev_controller *ctrl)
tty_driver_flush_buffer(tty);
}
-static int ttyport_write_room(struct serdev_controller *ctrl)
-{
- struct serport *serport = serdev_controller_get_drvdata(ctrl);
- struct tty_struct *tty = serport->tty;
-
- return tty_write_room(tty);
-}
-
static int ttyport_open(struct serdev_controller *ctrl)
{
struct serport *serport = serdev_controller_get_drvdata(ctrl);
@@ -259,7 +251,6 @@ static int ttyport_break_ctl(struct serdev_controller *ctrl, unsigned int break_
static const struct serdev_controller_ops ctrl_ops = {
.write_buf = ttyport_write_buf,
.write_flush = ttyport_write_flush,
- .write_room = ttyport_write_room,
.open = ttyport_open,
.close = ttyport_close,
.set_flow_control = ttyport_set_flow_control,
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 1aa3e55c8b47..b861585ca02a 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -9,7 +9,7 @@
#include <linux/bits.h>
#include <linux/serial_8250.h>
-#include <linux/serial_reg.h>
+#include <linux/serial_core.h>
#include <linux/dmaengine.h>
#include "../serial_mctrl_gpio.h"
@@ -93,6 +93,10 @@ struct serial8250_config {
#define UART_BUG_THRE BIT(3) /* UART has buggy THRE reassertion */
#define UART_BUG_TXRACE BIT(5) /* UART Tx fails to set remote DR */
+/* Module parameters */
+#define UART_NR CONFIG_SERIAL_8250_NR_UARTS
+
+extern unsigned int nr_uarts;
#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
#define SERIAL8250_SHARE_IRQS 1
@@ -100,6 +104,9 @@ struct serial8250_config {
#define SERIAL8250_SHARE_IRQS 0
#endif
+extern unsigned int share_irqs;
+extern unsigned int skip_txen_test;
+
#define SERIAL8250_PORT_FLAGS(_base, _irq, _flags) \
{ \
.iobase = _base, \
@@ -111,6 +118,19 @@ struct serial8250_config {
#define SERIAL8250_PORT(_base, _irq) SERIAL8250_PORT_FLAGS(_base, _irq, 0)
+extern struct uart_driver serial8250_reg;
+void serial8250_register_ports(struct uart_driver *drv, struct device *dev);
+
+/* Legacy ISA bus related APIs */
+typedef void (*serial8250_isa_config_fn)(int, struct uart_port *, u32 *);
+extern serial8250_isa_config_fn serial8250_isa_config;
+
+void serial8250_isa_init_ports(void);
+
+extern struct platform_device *serial8250_isa_devs;
+
+extern const struct uart_ops *univ8250_port_base_ops;
+extern struct uart_ops univ8250_port_ops;
static inline int serial_in(struct uart_8250_port *up, int offset)
{
@@ -200,6 +220,7 @@ static inline bool serial8250_clear_THRI(struct uart_8250_port *up)
return true;
}
+struct uart_8250_port *serial8250_setup_port(int index);
struct uart_8250_port *serial8250_get_port(int line);
void serial8250_rpm_get(struct uart_8250_port *p);
@@ -210,8 +231,8 @@ void serial8250_rpm_put_tx(struct uart_8250_port *p);
int serial8250_em485_config(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485);
-void serial8250_em485_start_tx(struct uart_8250_port *p);
-void serial8250_em485_stop_tx(struct uart_8250_port *p);
+void serial8250_em485_start_tx(struct uart_8250_port *p, bool toggle_ier);
+void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier);
void serial8250_em485_destroy(struct uart_8250_port *p);
extern struct serial_rs485 serial8250_em485_supported;
@@ -293,9 +314,6 @@ static inline int serial8250_in_MCR(struct uart_8250_port *up)
return mctrl;
}
-bool alpha_jensen(void);
-void alpha_jensen_set_mctrl(struct uart_port *port, unsigned int mctrl);
-
#ifdef CONFIG_SERIAL_8250_PNP
int serial8250_pnp_init(void);
void serial8250_pnp_exit(void);
@@ -304,6 +322,12 @@ static inline int serial8250_pnp_init(void) { return 0; }
static inline void serial8250_pnp_exit(void) { }
#endif
+#ifdef CONFIG_SERIAL_8250_RSA
+void univ8250_rsa_support(struct uart_ops *ops);
+#else
+static inline void univ8250_rsa_support(struct uart_ops *ops) { }
+#endif
+
#ifdef CONFIG_SERIAL_8250_FINTEK
int fintek_8250_probe(struct uart_8250_port *uart);
#else
@@ -350,6 +374,7 @@ static inline int is_omap1510_8250(struct uart_8250_port *pt)
#ifdef CONFIG_SERIAL_8250_DMA
extern int serial8250_tx_dma(struct uart_8250_port *);
+extern void serial8250_tx_dma_flush(struct uart_8250_port *);
extern int serial8250_rx_dma(struct uart_8250_port *);
extern void serial8250_rx_dma_flush(struct uart_8250_port *);
extern int serial8250_request_dma(struct uart_8250_port *);
@@ -382,6 +407,7 @@ static inline int serial8250_tx_dma(struct uart_8250_port *p)
{
return -1;
}
+static inline void serial8250_tx_dma_flush(struct uart_8250_port *p) { }
static inline int serial8250_rx_dma(struct uart_8250_port *p)
{
return -1;
diff --git a/drivers/tty/serial/8250/8250_alpha.c b/drivers/tty/serial/8250/8250_alpha.c
deleted file mode 100644
index 58e70328aa4d..000000000000
--- a/drivers/tty/serial/8250/8250_alpha.c
+++ /dev/null
@@ -1,21 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-
-#include <asm/machvec.h>
-#include "8250.h"
-
-bool alpha_jensen(void)
-{
- return !strcmp(alpha_mv.vector_name, "Jensen");
-}
-
-void alpha_jensen_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
- /*
- * Digital did something really horribly wrong with the OUT1 and OUT2
- * lines on Alpha Jensen. The failure mode is that if either is
- * cleared, the machine locks up with endless interrupts.
- */
- mctrl |= TIOCM_OUT1 | TIOCM_OUT2;
-
- serial8250_do_set_mctrl(port, mctrl);
-}
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c
index 53d8eee9b1c8..392447038bfb 100644
--- a/drivers/tty/serial/8250/8250_aspeed_vuart.c
+++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c
@@ -550,7 +550,7 @@ static void aspeed_vuart_remove(struct platform_device *pdev)
{
struct aspeed_vuart *vuart = platform_get_drvdata(pdev);
- del_timer_sync(&vuart->unthrottle_timer);
+ timer_delete_sync(&vuart->unthrottle_timer);
aspeed_vuart_set_enabled(vuart, false);
serial8250_unregister_port(vuart->line);
sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group);
@@ -561,6 +561,7 @@ static const struct of_device_id aspeed_vuart_table[] = {
{ .compatible = "aspeed,ast2500-vuart" },
{ },
};
+MODULE_DEVICE_TABLE(of, aspeed_vuart_table);
static struct platform_driver aspeed_vuart_driver = {
.driver = {
@@ -568,7 +569,7 @@ static struct platform_driver aspeed_vuart_driver = {
.of_match_table = aspeed_vuart_table,
},
.probe = aspeed_vuart_probe,
- .remove_new = aspeed_vuart_remove,
+ .remove = aspeed_vuart_remove,
};
module_platform_driver(aspeed_vuart_driver);
diff --git a/drivers/tty/serial/8250/8250_bcm2835aux.c b/drivers/tty/serial/8250/8250_bcm2835aux.c
index 121a5ce86050..0609582a62f7 100644
--- a/drivers/tty/serial/8250/8250_bcm2835aux.c
+++ b/drivers/tty/serial/8250/8250_bcm2835aux.c
@@ -13,6 +13,7 @@
*/
#include <linux/clk.h>
+#include <linux/console.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -45,7 +46,7 @@ struct bcm2835aux_data {
u32 cntl;
};
-static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
+static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up, bool toggle_ier)
{
if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
struct bcm2835aux_data *data = dev_get_drvdata(up->port.dev);
@@ -64,7 +65,7 @@ static void bcm2835aux_rs485_start_tx(struct uart_8250_port *up)
serial8250_out_MCR(up, UART_MCR_RTS);
}
-static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up)
+static void bcm2835aux_rs485_stop_tx(struct uart_8250_port *up, bool toggle_ier)
{
if (up->port.rs485.flags & SER_RS485_RTS_AFTER_SEND)
serial8250_out_MCR(up, 0);
@@ -213,14 +214,60 @@ static const struct acpi_device_id bcm2835aux_serial_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, bcm2835aux_serial_acpi_match);
+static bool bcm2835aux_can_disable_clock(struct device *dev)
+{
+ struct bcm2835aux_data *data = dev_get_drvdata(dev);
+ struct uart_8250_port *up = serial8250_get_port(data->line);
+
+ if (device_may_wakeup(dev))
+ return false;
+
+ if (uart_console(&up->port) && !console_suspend_enabled)
+ return false;
+
+ return true;
+}
+
+static int bcm2835aux_suspend(struct device *dev)
+{
+ struct bcm2835aux_data *data = dev_get_drvdata(dev);
+
+ serial8250_suspend_port(data->line);
+
+ if (!bcm2835aux_can_disable_clock(dev))
+ return 0;
+
+ clk_disable_unprepare(data->clk);
+ return 0;
+}
+
+static int bcm2835aux_resume(struct device *dev)
+{
+ struct bcm2835aux_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ if (bcm2835aux_can_disable_clock(dev)) {
+ ret = clk_prepare_enable(data->clk);
+ if (ret)
+ return ret;
+ }
+
+ serial8250_resume_port(data->line);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(bcm2835aux_dev_pm_ops, bcm2835aux_suspend, bcm2835aux_resume);
+
static struct platform_driver bcm2835aux_serial_driver = {
.driver = {
.name = "bcm2835-aux-uart",
.of_match_table = bcm2835aux_serial_match,
.acpi_match_table = bcm2835aux_serial_acpi_match,
+ .pm = pm_ptr(&bcm2835aux_dev_pm_ops),
},
.probe = bcm2835aux_serial_probe,
- .remove_new = bcm2835aux_serial_remove,
+ .remove = bcm2835aux_serial_remove,
};
module_platform_driver(bcm2835aux_serial_driver);
diff --git a/drivers/tty/serial/8250/8250_bcm7271.c b/drivers/tty/serial/8250/8250_bcm7271.c
index 5daa38d9c64e..742004d63c6f 100644
--- a/drivers/tty/serial/8250/8250_bcm7271.c
+++ b/drivers/tty/serial/8250/8250_bcm7271.c
@@ -413,20 +413,18 @@ static int stop_tx_dma(struct uart_8250_port *p)
static int brcmuart_tx_dma(struct uart_8250_port *p)
{
struct brcmuart_priv *priv = p->port.private_data;
- struct circ_buf *xmit = &p->port.state->xmit;
+ struct tty_port *tport = &p->port.state->port;
u32 tx_size;
if (uart_tx_stopped(&p->port) || priv->tx_running ||
- uart_circ_empty(xmit)) {
+ kfifo_is_empty(&tport->xmit_fifo)) {
return 0;
}
- tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
priv->dma.tx_err = 0;
- memcpy(priv->tx_buf, &xmit->buf[xmit->tail], tx_size);
- uart_xmit_advance(&p->port, tx_size);
+ tx_size = uart_fifo_out(&p->port, priv->tx_buf, UART_XMIT_SIZE);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&p->port);
udma_writel(priv, REGS_DMA_TX, UDMA_TX_TRANSFER_LEN, tx_size);
@@ -540,7 +538,7 @@ static void brcmuart_tx_isr(struct uart_port *up, u32 isr)
struct brcmuart_priv *priv = up->private_data;
struct device *dev = up->dev;
struct uart_8250_port *port_8250 = up_to_u8250p(up);
- struct circ_buf *xmit = &port_8250->port.state->xmit;
+ struct tty_port *tport = &port_8250->port.state->port;
if (isr & UDMA_INTR_TX_ABORT) {
if (priv->tx_running)
@@ -548,7 +546,7 @@ static void brcmuart_tx_isr(struct uart_port *up, u32 isr)
return;
}
priv->tx_running = false;
- if (!uart_circ_empty(xmit) && !uart_tx_stopped(up))
+ if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(up))
brcmuart_tx_dma(port_8250);
}
@@ -675,18 +673,46 @@ static void init_real_clk_rates(struct device *dev, struct brcmuart_priv *priv)
clk_set_rate(priv->baud_mux_clk, priv->default_mux_rate);
}
+static u32 find_quot(struct device *dev, u32 freq, u32 baud, u32 *percent)
+{
+ u32 quot;
+ u32 rate;
+ u64 hires_rate;
+ u64 hires_baud;
+ u64 hires_err;
+
+ rate = freq / 16;
+ quot = DIV_ROUND_CLOSEST(rate, baud);
+ if (!quot)
+ return 0;
+
+ /* increase resolution to get xx.xx percent */
+ hires_rate = div_u64((u64)rate * 10000, (u64)quot);
+ hires_baud = (u64)baud * 10000;
+
+ /* get the delta */
+ if (hires_rate > hires_baud)
+ hires_err = (hires_rate - hires_baud);
+ else
+ hires_err = (hires_baud - hires_rate);
+
+ *percent = (unsigned long)DIV_ROUND_CLOSEST_ULL(hires_err, baud);
+
+ dev_dbg(dev, "Baud rate: %u, MUX Clk: %u, Error: %u.%u%%\n",
+ baud, freq, *percent / 100, *percent % 100);
+
+ return quot;
+}
+
static void set_clock_mux(struct uart_port *up, struct brcmuart_priv *priv,
u32 baud)
{
u32 percent;
u32 best_percent = UINT_MAX;
u32 quot;
+ u32 freq;
u32 best_quot = 1;
- u32 rate;
- int best_index = -1;
- u64 hires_rate;
- u64 hires_baud;
- u64 hires_err;
+ u32 best_freq = 0;
int rc;
int i;
int real_baud;
@@ -695,44 +721,35 @@ static void set_clock_mux(struct uart_port *up, struct brcmuart_priv *priv,
if (priv->baud_mux_clk == NULL)
return;
- /* Find the closest match for specified baud */
- for (i = 0; i < ARRAY_SIZE(priv->real_rates); i++) {
- if (priv->real_rates[i] == 0)
- continue;
- rate = priv->real_rates[i] / 16;
- quot = DIV_ROUND_CLOSEST(rate, baud);
- if (!quot)
- continue;
-
- /* increase resolution to get xx.xx percent */
- hires_rate = (u64)rate * 10000;
- hires_baud = (u64)baud * 10000;
-
- hires_err = div_u64(hires_rate, (u64)quot);
-
- /* get the delta */
- if (hires_err > hires_baud)
- hires_err = (hires_err - hires_baud);
- else
- hires_err = (hires_baud - hires_err);
-
- percent = (unsigned long)DIV_ROUND_CLOSEST_ULL(hires_err, baud);
- dev_dbg(up->dev,
- "Baud rate: %u, MUX Clk: %u, Error: %u.%u%%\n",
- baud, priv->real_rates[i], percent / 100,
- percent % 100);
- if (percent < best_percent) {
- best_percent = percent;
- best_index = i;
- best_quot = quot;
+ /* Try default_mux_rate first */
+ quot = find_quot(up->dev, priv->default_mux_rate, baud, &percent);
+ if (quot) {
+ best_percent = percent;
+ best_freq = priv->default_mux_rate;
+ best_quot = quot;
+ }
+ /* If more than 1% error, find the closest match for specified baud */
+ if (best_percent > 100) {
+ for (i = 0; i < ARRAY_SIZE(priv->real_rates); i++) {
+ freq = priv->real_rates[i];
+ if (freq == 0 || freq == priv->default_mux_rate)
+ continue;
+ quot = find_quot(up->dev, freq, baud, &percent);
+ if (!quot)
+ continue;
+
+ if (percent < best_percent) {
+ best_percent = percent;
+ best_freq = freq;
+ best_quot = quot;
+ }
}
}
- if (best_index == -1) {
+ if (!best_freq) {
dev_err(up->dev, "Error, %d BAUD rate is too fast.\n", baud);
return;
}
- rate = priv->real_rates[best_index];
- rc = clk_set_rate(priv->baud_mux_clk, rate);
+ rc = clk_set_rate(priv->baud_mux_clk, best_freq);
if (rc)
dev_err(up->dev, "Error selecting BAUD MUX clock\n");
@@ -741,8 +758,8 @@ static void set_clock_mux(struct uart_port *up, struct brcmuart_priv *priv,
dev_err(up->dev, "Error, baud: %d has %u.%u%% error\n",
baud, percent / 100, percent % 100);
- real_baud = rate / 16 / best_quot;
- dev_dbg(up->dev, "Selecting BAUD MUX rate: %u\n", rate);
+ real_baud = best_freq / 16 / best_quot;
+ dev_dbg(up->dev, "Selecting BAUD MUX rate: %u\n", best_freq);
dev_dbg(up->dev, "Requested baud: %u, Actual baud: %u\n",
baud, real_baud);
@@ -751,7 +768,7 @@ static void set_clock_mux(struct uart_port *up, struct brcmuart_priv *priv,
i += (i / 2);
priv->char_wait = ns_to_ktime(i);
- up->uartclk = rate;
+ up->uartclk = best_freq;
}
static void brcmstb_set_termios(struct uart_port *up,
@@ -795,7 +812,7 @@ static int brcmuart_handle_irq(struct uart_port *p)
/*
* if Receive Data Interrupt is enabled and
* we're uing hardware flow control, deassert
- * RTS and wait for any chars in the pipline to
+ * RTS and wait for any chars in the pipeline to
* arrive and then check for DR again.
*/
if ((ier & UART_IER_RDI) && (up->mcr & UART_MCR_AFE)) {
@@ -1039,8 +1056,7 @@ static int brcmuart_probe(struct platform_device *pdev)
}
/* setup HR timer */
- hrtimer_init(&priv->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
- priv->hrt.function = brcmuart_hrtimer_func;
+ hrtimer_setup(&priv->hrt, brcmuart_hrtimer_func, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
up.port.shutdown = brcmuart_shutdown;
up.port.startup = brcmuart_startup;
@@ -1187,7 +1203,7 @@ static struct platform_driver brcmuart_platform_driver = {
.of_match_table = brcmuart_dt_ids,
},
.probe = brcmuart_probe,
- .remove_new = brcmuart_remove,
+ .remove = brcmuart_remove,
};
static int __init brcmuart_init(void)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index b62ad9006780..5a56f853cf6d 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -6,11 +6,9 @@
*
* Copyright (C) 2001 Russell King.
*
- * Supports: ISA-compatible 8250/16550 ports
- * PNP 8250/16550 ports
+ * Supports:
* early_serial_setup() ports
* userspace-configurable "phantom" ports
- * "serial8250" platform devices
* serial8250_register_8250_port() ports
*/
@@ -35,52 +33,13 @@
#include <linux/string_helpers.h>
#include <linux/uaccess.h>
#include <linux/io.h>
-#ifdef CONFIG_SPARC
-#include <linux/sunserialcore.h>
-#endif
#include <asm/irq.h>
#include "8250.h"
-/*
- * Configuration:
- * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option
- * is unsafe when used on edge-triggered interrupts.
- */
-static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
-
-static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
-
-static struct uart_driver serial8250_reg;
-
-static unsigned int skip_txen_test; /* force skip of txen test at init time */
-
#define PASS_LIMIT 512
-#include <asm/serial.h>
-/*
- * SERIAL_PORT_DFNS tells us about built-in ports that have no
- * standard enumeration mechanism. Platforms that can find all
- * serial ports via mechanisms like ACPI or PCI need not supply it.
- */
-#ifndef SERIAL_PORT_DFNS
-#define SERIAL_PORT_DFNS
-#endif
-
-static const struct old_serial_port old_serial_port[] = {
- SERIAL_PORT_DFNS /* defined in asm/serial.h */
-};
-
-#define UART_NR CONFIG_SERIAL_8250_NR_UARTS
-
-#ifdef CONFIG_SERIAL_8250_RSA
-
-#define PORT_RSA_MAX 4
-static unsigned long probe_rsa[PORT_RSA_MAX];
-static unsigned int probe_rsa_count;
-#endif /* CONFIG_SERIAL_8250_RSA */
-
struct irq_info {
struct hlist_node node;
int irq;
@@ -280,7 +239,8 @@ static void serial8250_backup_timeout(struct timer_list *t)
*/
lsr = serial_lsr_in(up);
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
- (!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
+ (!kfifo_is_empty(&up->port.state->port.xmit_fifo) ||
+ up->port.x_char) &&
(lsr & UART_LSR_THRE)) {
iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
iir |= UART_IIR_THRI;
@@ -338,51 +298,14 @@ static void univ8250_release_irq(struct uart_8250_port *up)
{
struct uart_port *port = &up->port;
- del_timer_sync(&up->timer);
+ timer_delete_sync(&up->timer);
up->timer.function = serial8250_timeout;
if (port->irq)
serial_unlink_irq_chain(up);
}
-#ifdef CONFIG_SERIAL_8250_RSA
-static int serial8250_request_rsa_resource(struct uart_8250_port *up)
-{
- unsigned long start = UART_RSA_BASE << up->port.regshift;
- unsigned int size = 8 << up->port.regshift;
- struct uart_port *port = &up->port;
- int ret = -EINVAL;
-
- switch (port->iotype) {
- case UPIO_HUB6:
- case UPIO_PORT:
- start += port->iobase;
- if (request_region(start, size, "serial-rsa"))
- ret = 0;
- else
- ret = -EBUSY;
- break;
- }
-
- return ret;
-}
-
-static void serial8250_release_rsa_resource(struct uart_8250_port *up)
-{
- unsigned long offset = UART_RSA_BASE << up->port.regshift;
- unsigned int size = 8 << up->port.regshift;
- struct uart_port *port = &up->port;
-
- switch (port->iotype) {
- case UPIO_HUB6:
- case UPIO_PORT:
- release_region(port->iobase + offset, size);
- break;
- }
-}
-#endif
-
-static const struct uart_ops *base_ops;
-static struct uart_ops univ8250_port_ops;
+const struct uart_ops *univ8250_port_base_ops = NULL;
+struct uart_ops univ8250_port_ops;
static const struct uart_8250_ops univ8250_driver_ops = {
.setup_irq = univ8250_setup_irq,
@@ -410,85 +333,12 @@ struct uart_8250_port *serial8250_get_port(int line)
}
EXPORT_SYMBOL_GPL(serial8250_get_port);
-static void (*serial8250_isa_config)(int port, struct uart_port *up,
- u32 *capabilities);
-
-void serial8250_set_isa_configurator(
- void (*v)(int port, struct uart_port *up, u32 *capabilities))
-{
- serial8250_isa_config = v;
-}
-EXPORT_SYMBOL(serial8250_set_isa_configurator);
-
-#ifdef CONFIG_SERIAL_8250_RSA
-
-static void univ8250_config_port(struct uart_port *port, int flags)
-{
- struct uart_8250_port *up = up_to_u8250p(port);
-
- up->probe &= ~UART_PROBE_RSA;
- if (port->type == PORT_RSA) {
- if (serial8250_request_rsa_resource(up) == 0)
- up->probe |= UART_PROBE_RSA;
- } else if (flags & UART_CONFIG_TYPE) {
- int i;
-
- for (i = 0; i < probe_rsa_count; i++) {
- if (probe_rsa[i] == up->port.iobase) {
- if (serial8250_request_rsa_resource(up) == 0)
- up->probe |= UART_PROBE_RSA;
- break;
- }
- }
- }
-
- base_ops->config_port(port, flags);
-
- if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA)
- serial8250_release_rsa_resource(up);
-}
-
-static int univ8250_request_port(struct uart_port *port)
-{
- struct uart_8250_port *up = up_to_u8250p(port);
- int ret;
-
- ret = base_ops->request_port(port);
- if (ret == 0 && port->type == PORT_RSA) {
- ret = serial8250_request_rsa_resource(up);
- if (ret < 0)
- base_ops->release_port(port);
- }
-
- return ret;
-}
-
-static void univ8250_release_port(struct uart_port *port)
-{
- struct uart_8250_port *up = up_to_u8250p(port);
-
- if (port->type == PORT_RSA)
- serial8250_release_rsa_resource(up);
- base_ops->release_port(port);
-}
-
-static void univ8250_rsa_support(struct uart_ops *ops)
-{
- ops->config_port = univ8250_config_port;
- ops->request_port = univ8250_request_port;
- ops->release_port = univ8250_release_port;
-}
-
-#else
-#define univ8250_rsa_support(x) do { } while (0)
-#endif /* CONFIG_SERIAL_8250_RSA */
-
static inline void serial8250_apply_quirks(struct uart_8250_port *up)
{
up->port.quirks |= skip_txen_test ? UPQ_NO_TXEN_TEST : 0;
}
-static struct uart_8250_port *serial8250_setup_port(int index)
+struct uart_8250_port *serial8250_setup_port(int index)
{
struct uart_8250_port *up;
@@ -500,74 +350,20 @@ static struct uart_8250_port *serial8250_setup_port(int index)
up->port.port_id = index;
serial8250_init_port(up);
- if (!base_ops)
- base_ops = up->port.ops;
+ if (!univ8250_port_base_ops)
+ univ8250_port_base_ops = up->port.ops;
up->port.ops = &univ8250_port_ops;
timer_setup(&up->timer, serial8250_timeout, 0);
up->ops = &univ8250_driver_ops;
- if (IS_ENABLED(CONFIG_ALPHA_JENSEN) ||
- (IS_ENABLED(CONFIG_ALPHA_GENERIC) && alpha_jensen()))
- up->port.set_mctrl = alpha_jensen_set_mctrl;
-
serial8250_set_defaults(up);
return up;
}
-static void __init serial8250_isa_init_ports(void)
-{
- struct uart_8250_port *up;
- static int first = 1;
- int i, irqflag = 0;
-
- if (!first)
- return;
- first = 0;
-
- if (nr_uarts > UART_NR)
- nr_uarts = UART_NR;
-
- /*
- * Set up initial isa ports based on nr_uart module param, or else
- * default to CONFIG_SERIAL_8250_RUNTIME_UARTS. Note that we do not
- * need to increase nr_uarts when setting up the initial isa ports.
- */
- for (i = 0; i < nr_uarts; i++)
- serial8250_setup_port(i);
-
- /* chain base port ops to support Remote Supervisor Adapter */
- univ8250_port_ops = *base_ops;
- univ8250_rsa_support(&univ8250_port_ops);
-
- if (share_irqs)
- irqflag = IRQF_SHARED;
-
- for (i = 0, up = serial8250_ports;
- i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
- i++, up++) {
- struct uart_port *port = &up->port;
-
- port->iobase = old_serial_port[i].port;
- port->irq = irq_canonicalize(old_serial_port[i].irq);
- port->irqflags = 0;
- port->uartclk = old_serial_port[i].baud_base * 16;
- port->flags = old_serial_port[i].flags;
- port->hub6 = 0;
- port->membase = old_serial_port[i].iomem_base;
- port->iotype = old_serial_port[i].io_type;
- port->regshift = old_serial_port[i].iomem_reg_shift;
-
- port->irqflags |= irqflag;
- if (serial8250_isa_config != NULL)
- serial8250_isa_config(i, &up->port, &up->capabilities);
- }
-}
-
-static void __init
-serial8250_register_ports(struct uart_driver *drv, struct device *dev)
+void __init serial8250_register_ports(struct uart_driver *drv, struct device *dev)
{
int i;
@@ -627,11 +423,11 @@ static int univ8250_console_setup(struct console *co, char *options)
port = &serial8250_ports[co->index].port;
/* link port to console */
- port->cons = co;
+ uart_port_set_cons(port, co);
retval = serial8250_console_setup(port, options, false);
if (retval != 0)
- port->cons = NULL;
+ uart_port_set_cons(port, NULL);
return retval;
}
@@ -689,7 +485,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx,
continue;
co->index = i;
- port->cons = co;
+ uart_port_set_cons(port, co);
return serial8250_console_setup(port, options, true);
}
@@ -724,7 +520,7 @@ console_initcall(univ8250_console_init);
#define SERIAL8250_CONSOLE NULL
#endif
-static struct uart_driver serial8250_reg = {
+struct uart_driver serial8250_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
.dev_name = "ttyS",
@@ -826,120 +622,6 @@ void serial8250_resume_port(int line)
EXPORT_SYMBOL(serial8250_resume_port);
/*
- * Register a set of serial devices attached to a platform device. The
- * list is terminated with a zero flags entry, which means we expect
- * all entries to have at least UPF_BOOT_AUTOCONF set.
- */
-static int serial8250_probe(struct platform_device *dev)
-{
- struct plat_serial8250_port *p = dev_get_platdata(&dev->dev);
- struct uart_8250_port uart;
- int ret, i, irqflag = 0;
-
- memset(&uart, 0, sizeof(uart));
-
- if (share_irqs)
- irqflag = IRQF_SHARED;
-
- for (i = 0; p && p->flags != 0; p++, i++) {
- uart.port.iobase = p->iobase;
- uart.port.membase = p->membase;
- uart.port.irq = p->irq;
- uart.port.irqflags = p->irqflags;
- uart.port.uartclk = p->uartclk;
- uart.port.regshift = p->regshift;
- uart.port.iotype = p->iotype;
- uart.port.flags = p->flags;
- uart.port.mapbase = p->mapbase;
- uart.port.mapsize = p->mapsize;
- uart.port.hub6 = p->hub6;
- uart.port.has_sysrq = p->has_sysrq;
- uart.port.private_data = p->private_data;
- uart.port.type = p->type;
- uart.bugs = p->bugs;
- uart.port.serial_in = p->serial_in;
- uart.port.serial_out = p->serial_out;
- uart.dl_read = p->dl_read;
- uart.dl_write = p->dl_write;
- uart.port.handle_irq = p->handle_irq;
- uart.port.handle_break = p->handle_break;
- uart.port.set_termios = p->set_termios;
- uart.port.set_ldisc = p->set_ldisc;
- uart.port.get_mctrl = p->get_mctrl;
- uart.port.pm = p->pm;
- uart.port.dev = &dev->dev;
- uart.port.irqflags |= irqflag;
- ret = serial8250_register_8250_port(&uart);
- if (ret < 0) {
- dev_err(&dev->dev, "unable to register port at index %d "
- "(IO%lx MEM%llx IRQ%d): %d\n", i,
- p->iobase, (unsigned long long)p->mapbase,
- p->irq, ret);
- }
- }
- return 0;
-}
-
-/*
- * Remove serial ports registered against a platform device.
- */
-static void serial8250_remove(struct platform_device *dev)
-{
- int i;
-
- for (i = 0; i < nr_uarts; i++) {
- struct uart_8250_port *up = &serial8250_ports[i];
-
- if (up->port.dev == &dev->dev)
- serial8250_unregister_port(i);
- }
-}
-
-static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
-{
- int i;
-
- for (i = 0; i < UART_NR; i++) {
- struct uart_8250_port *up = &serial8250_ports[i];
-
- if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
- uart_suspend_port(&serial8250_reg, &up->port);
- }
-
- return 0;
-}
-
-static int serial8250_resume(struct platform_device *dev)
-{
- int i;
-
- for (i = 0; i < UART_NR; i++) {
- struct uart_8250_port *up = &serial8250_ports[i];
-
- if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
- serial8250_resume_port(i);
- }
-
- return 0;
-}
-
-static struct platform_driver serial8250_isa_driver = {
- .probe = serial8250_probe,
- .remove_new = serial8250_remove,
- .suspend = serial8250_suspend,
- .resume = serial8250_resume,
- .driver = {
- .name = "serial8250",
- },
-};
-
-/*
- * This "device" covers _all_ ISA 8250-compatible serial devices listed
- * in the table in include/asm/serial.h
- */
-static struct platform_device *serial8250_isa_devs;
-
-/*
* serial8250_register_8250_port and serial8250_unregister_port allows for
* 16x50 serial ports to be configured at run-time, to support PCMCIA
* modems and PCI multiport cards.
@@ -993,7 +675,6 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
uart_port_lock_irqsave(port, &flags);
up->ier |= UART_IER_RLSI | UART_IER_RDI;
- up->port.read_status_mask |= UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
uart_port_unlock_irqrestore(port, flags);
}
@@ -1130,6 +811,9 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
uart->dl_write = up->dl_write;
if (uart->port.type != PORT_8250_CIR) {
+ if (uart_console_registered(&uart->port))
+ pm_runtime_get_sync(uart->port.dev);
+
if (serial8250_isa_config != NULL)
serial8250_isa_config(0, &uart->port,
&uart->capabilities);
@@ -1215,134 +899,5 @@ void serial8250_unregister_port(int line)
}
EXPORT_SYMBOL(serial8250_unregister_port);
-static int __init serial8250_init(void)
-{
- int ret;
-
- if (nr_uarts == 0)
- return -ENODEV;
-
- serial8250_isa_init_ports();
-
- pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %s\n",
- nr_uarts, str_enabled_disabled(share_irqs));
-
-#ifdef CONFIG_SPARC
- ret = sunserial_register_minors(&serial8250_reg, UART_NR);
-#else
- serial8250_reg.nr = UART_NR;
- ret = uart_register_driver(&serial8250_reg);
-#endif
- if (ret)
- goto out;
-
- ret = serial8250_pnp_init();
- if (ret)
- goto unreg_uart_drv;
-
- serial8250_isa_devs = platform_device_alloc("serial8250",
- PLAT8250_DEV_LEGACY);
- if (!serial8250_isa_devs) {
- ret = -ENOMEM;
- goto unreg_pnp;
- }
-
- ret = platform_device_add(serial8250_isa_devs);
- if (ret)
- goto put_dev;
-
- serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
-
- ret = platform_driver_register(&serial8250_isa_driver);
- if (ret == 0)
- goto out;
-
- platform_device_del(serial8250_isa_devs);
-put_dev:
- platform_device_put(serial8250_isa_devs);
-unreg_pnp:
- serial8250_pnp_exit();
-unreg_uart_drv:
-#ifdef CONFIG_SPARC
- sunserial_unregister_minors(&serial8250_reg, UART_NR);
-#else
- uart_unregister_driver(&serial8250_reg);
-#endif
-out:
- return ret;
-}
-
-static void __exit serial8250_exit(void)
-{
- struct platform_device *isa_dev = serial8250_isa_devs;
-
- /*
- * This tells serial8250_unregister_port() not to re-register
- * the ports (thereby making serial8250_isa_driver permanently
- * in use.)
- */
- serial8250_isa_devs = NULL;
-
- platform_driver_unregister(&serial8250_isa_driver);
- platform_device_unregister(isa_dev);
-
- serial8250_pnp_exit();
-
-#ifdef CONFIG_SPARC
- sunserial_unregister_minors(&serial8250_reg, UART_NR);
-#else
- uart_unregister_driver(&serial8250_reg);
-#endif
-}
-
-module_init(serial8250_init);
-module_exit(serial8250_exit);
-
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
-
-module_param_hw(share_irqs, uint, other, 0644);
-MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)");
-
-module_param(nr_uarts, uint, 0644);
-MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
-
-module_param(skip_txen_test, uint, 0644);
-MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
-
-#ifdef CONFIG_SERIAL_8250_RSA
-module_param_hw_array(probe_rsa, ulong, ioport, &probe_rsa_count, 0444);
-MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
-#endif
-MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
-
-#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
-#ifndef MODULE
-/* This module was renamed to 8250_core in 3.7. Keep the old "8250" name
- * working as well for the module options so we don't break people. We
- * need to keep the names identical and the convenient macros will happily
- * refuse to let us do that by failing the build with redefinition errors
- * of global variables. So we stick them inside a dummy function to avoid
- * those conflicts. The options still get parsed, and the redefined
- * MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
- *
- * This is hacky. I'm sorry.
- */
-static void __used s8250_options(void)
-{
-#undef MODULE_PARAM_PREFIX
-#define MODULE_PARAM_PREFIX "8250_core."
-
- module_param_cb(share_irqs, &param_ops_uint, &share_irqs, 0644);
- module_param_cb(nr_uarts, &param_ops_uint, &nr_uarts, 0644);
- module_param_cb(skip_txen_test, &param_ops_uint, &skip_txen_test, 0644);
-#ifdef CONFIG_SERIAL_8250_RSA
- __module_param_call(MODULE_PARAM_PREFIX, probe_rsa,
- &param_array_ops, .arr = &__param_arr_probe_rsa,
- 0444, -1, 0);
-#endif
-}
-#else
-MODULE_ALIAS("8250_core");
-#endif
-#endif
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index 8b30ca8fdd3f..bdd26c9f34bd 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -15,7 +15,7 @@ static void __dma_tx_complete(void *param)
{
struct uart_8250_port *p = param;
struct uart_8250_dma *dma = p->dma;
- struct circ_buf *xmit = &p->port.state->xmit;
+ struct tty_port *tport = &p->port.state->port;
unsigned long flags;
int ret;
@@ -28,7 +28,7 @@ static void __dma_tx_complete(void *param)
uart_xmit_advance(&p->port, dma->tx_size);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&p->port);
ret = serial8250_tx_dma(p);
@@ -86,9 +86,12 @@ static void dma_rx_complete(void *param)
int serial8250_tx_dma(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
- struct circ_buf *xmit = &p->port.state->xmit;
+ struct tty_port *tport = &p->port.state->port;
struct dma_async_tx_descriptor *desc;
struct uart_port *up = &p->port;
+ struct scatterlist *sg;
+ struct scatterlist sgl[2];
+ int i;
int ret;
if (dma->tx_running) {
@@ -102,19 +105,26 @@ int serial8250_tx_dma(struct uart_8250_port *p)
uart_xchar_out(up, UART_TX);
}
- if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
+ if (uart_tx_stopped(&p->port) || kfifo_is_empty(&tport->xmit_fifo)) {
/* We have been called from __dma_tx_complete() */
return 0;
}
- dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
-
serial8250_do_prepare_tx_dma(p);
- desc = dmaengine_prep_slave_single(dma->txchan,
- dma->tx_addr + xmit->tail,
- dma->tx_size, DMA_MEM_TO_DEV,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ sg_init_table(sgl, ARRAY_SIZE(sgl));
+
+ ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, sgl, ARRAY_SIZE(sgl),
+ UART_XMIT_SIZE, dma->tx_addr);
+
+ dma->tx_size = 0;
+
+ for_each_sg(sgl, sg, ret, i)
+ dma->tx_size += sg_dma_len(sg);
+
+ desc = dmaengine_prep_slave_sg(dma->txchan, sgl, ret,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
ret = -EBUSY;
goto err;
@@ -139,6 +149,22 @@ err:
return ret;
}
+void serial8250_tx_dma_flush(struct uart_8250_port *p)
+{
+ struct uart_8250_dma *dma = p->dma;
+
+ if (!dma->tx_running)
+ return;
+
+ /*
+ * kfifo_reset() has been called by the serial core, avoid
+ * advancing and underflowing in __dma_tx_complete().
+ */
+ dma->tx_size = 0;
+
+ dmaengine_terminate_async(dma->txchan);
+}
+
int serial8250_rx_dma(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
@@ -253,7 +279,7 @@ int serial8250_request_dma(struct uart_8250_port *p)
/* TX buffer */
dma->tx_addr = dma_map_single(dma->txchan->device->dev,
- p->port.state->xmit.buf,
+ p->port.state->port.xmit_buf,
UART_XMIT_SIZE,
DMA_TO_DEVICE);
if (dma_mapping_error(dma->txchan->device->dev, dma->tx_addr)) {
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 1300c92b8702..1902f29444a1 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -55,6 +55,34 @@
#define DW_UART_QUIRK_SKIP_SET_RATE BIT(2)
#define DW_UART_QUIRK_IS_DMA_FC BIT(3)
#define DW_UART_QUIRK_APMC0D08 BIT(4)
+#define DW_UART_QUIRK_CPR_VALUE BIT(5)
+
+struct dw8250_platform_data {
+ u8 usr_reg;
+ u32 cpr_value;
+ unsigned int quirks;
+};
+
+struct dw8250_data {
+ struct dw8250_port_data data;
+ const struct dw8250_platform_data *pdata;
+
+ int msr_mask_on;
+ int msr_mask_off;
+ struct clk *clk;
+ struct clk *pclk;
+ struct notifier_block clk_notifier;
+ struct work_struct clk_work;
+ struct reset_control *rst;
+
+ unsigned int skip_autocfg:1;
+ unsigned int uart_16550_compatible:1;
+};
+
+static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data)
+{
+ return container_of(data, struct dw8250_data, data);
+}
static inline struct dw8250_data *clk_to_dw8250_data(struct notifier_block *nb)
{
@@ -79,11 +107,23 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
return value;
}
+/*
+ * This function is being called as part of the uart_port::serial_out()
+ * routine. Hence, it must not call serial_port_out() or serial_out()
+ * against the modified registers here, i.e. LCR.
+ */
static void dw8250_force_idle(struct uart_port *p)
{
struct uart_8250_port *up = up_to_u8250p(p);
unsigned int lsr;
+ /*
+ * The following call currently performs serial_out()
+ * against the FCR register. Because it differs to LCR
+ * there will be no infinite loop, but if it ever gets
+ * modified, we might need a new custom version of it
+ * that avoids infinite recursion.
+ */
serial8250_clear_and_reinit_fifos(up);
/*
@@ -92,22 +132,31 @@ static void dw8250_force_idle(struct uart_port *p)
* enabled.
*/
if (up->fcr & UART_FCR_ENABLE_FIFO) {
- lsr = p->serial_in(p, UART_LSR);
+ lsr = serial_port_in(p, UART_LSR);
if (!(lsr & UART_LSR_DR))
return;
}
- (void)p->serial_in(p, UART_RX);
+ serial_port_in(p, UART_RX);
}
-static void dw8250_check_lcr(struct uart_port *p, int value)
+/*
+ * This function is being called as part of the uart_port::serial_out()
+ * routine. Hence, it must not call serial_port_out() or serial_out()
+ * against the modified registers here, i.e. LCR.
+ */
+static void dw8250_check_lcr(struct uart_port *p, int offset, int value)
{
- void __iomem *offset = p->membase + (UART_LCR << p->regshift);
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ void __iomem *addr = p->membase + (offset << p->regshift);
int tries = 1000;
+ if (offset != UART_LCR || d->uart_16550_compatible)
+ return;
+
/* Make sure LCR write wasn't ignored */
while (tries--) {
- unsigned int lcr = p->serial_in(p, UART_LCR);
+ unsigned int lcr = serial_port_in(p, offset);
if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
return;
@@ -116,15 +165,15 @@ static void dw8250_check_lcr(struct uart_port *p, int value)
#ifdef CONFIG_64BIT
if (p->type == PORT_OCTEON)
- __raw_writeq(value & 0xff, offset);
+ __raw_writeq(value & 0xff, addr);
else
#endif
if (p->iotype == UPIO_MEM32)
- writel(value, offset);
+ writel(value, addr);
else if (p->iotype == UPIO_MEM32BE)
- iowrite32be(value, offset);
+ iowrite32be(value, addr);
else
- writeb(value, offset);
+ writeb(value, addr);
}
/*
* FIXME: this deadlocks if port->lock is already held
@@ -158,12 +207,8 @@ static void dw8250_tx_wait_empty(struct uart_port *p)
static void dw8250_serial_out(struct uart_port *p, int offset, int value)
{
- struct dw8250_data *d = to_dw8250_data(p->private_data);
-
writeb(value, p->membase + (offset << p->regshift));
-
- if (offset == UART_LCR && !d->uart_16550_compatible)
- dw8250_check_lcr(p, value);
+ dw8250_check_lcr(p, offset, value);
}
static void dw8250_serial_out38x(struct uart_port *p, int offset, int value)
@@ -185,35 +230,26 @@ static unsigned int dw8250_serial_in(struct uart_port *p, int offset)
#ifdef CONFIG_64BIT
static unsigned int dw8250_serial_inq(struct uart_port *p, int offset)
{
- unsigned int value;
-
- value = (u8)__raw_readq(p->membase + (offset << p->regshift));
+ u8 value = __raw_readq(p->membase + (offset << p->regshift));
return dw8250_modify_msr(p, offset, value);
}
static void dw8250_serial_outq(struct uart_port *p, int offset, int value)
{
- struct dw8250_data *d = to_dw8250_data(p->private_data);
-
value &= 0xff;
__raw_writeq(value, p->membase + (offset << p->regshift));
/* Read back to ensure register write ordering. */
__raw_readq(p->membase + (UART_LCR << p->regshift));
- if (offset == UART_LCR && !d->uart_16550_compatible)
- dw8250_check_lcr(p, value);
+ dw8250_check_lcr(p, offset, value);
}
#endif /* CONFIG_64BIT */
static void dw8250_serial_out32(struct uart_port *p, int offset, int value)
{
- struct dw8250_data *d = to_dw8250_data(p->private_data);
-
writel(value, p->membase + (offset << p->regshift));
-
- if (offset == UART_LCR && !d->uart_16550_compatible)
- dw8250_check_lcr(p, value);
+ dw8250_check_lcr(p, offset, value);
}
static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
@@ -225,12 +261,8 @@ static unsigned int dw8250_serial_in32(struct uart_port *p, int offset)
static void dw8250_serial_out32be(struct uart_port *p, int offset, int value)
{
- struct dw8250_data *d = to_dw8250_data(p->private_data);
-
iowrite32be(value, p->membase + (offset << p->regshift));
-
- if (offset == UART_LCR && !d->uart_16550_compatible)
- dw8250_check_lcr(p, value);
+ dw8250_check_lcr(p, offset, value);
}
static unsigned int dw8250_serial_in32be(struct uart_port *p, int offset)
@@ -245,7 +277,7 @@ static int dw8250_handle_irq(struct uart_port *p)
{
struct uart_8250_port *up = up_to_u8250p(p);
struct dw8250_data *d = to_dw8250_data(p->private_data);
- unsigned int iir = p->serial_in(p, UART_IIR);
+ unsigned int iir = serial_port_in(p, UART_IIR);
bool rx_timeout = (iir & 0x3f) == UART_IIR_RX_TIMEOUT;
unsigned int quirks = d->pdata->quirks;
unsigned int status;
@@ -266,7 +298,7 @@ static int dw8250_handle_irq(struct uart_port *p)
status = serial_lsr_in(up);
if (!(status & (UART_LSR_DR | UART_LSR_BI)))
- (void) p->serial_in(p, UART_RX);
+ serial_port_in(p, UART_RX);
uart_port_unlock_irqrestore(p, flags);
}
@@ -288,7 +320,7 @@ static int dw8250_handle_irq(struct uart_port *p)
if ((iir & UART_IIR_BUSY) == UART_IIR_BUSY) {
/* Clear the USR */
- (void)p->serial_in(p, d->pdata->usr_reg);
+ serial_port_in(p, d->pdata->usr_reg);
return 1;
}
@@ -375,7 +407,7 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios,
static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
{
struct uart_8250_port *up = up_to_u8250p(p);
- unsigned int mcr = p->serial_in(p, UART_MCR);
+ unsigned int mcr = serial_port_in(p, UART_MCR);
if (up->capabilities & UART_CAP_IRDA) {
if (termios->c_line == N_IRDA)
@@ -383,7 +415,7 @@ static void dw8250_set_ldisc(struct uart_port *p, struct ktermios *termios)
else
mcr &= ~DW_UART_MCR_SIRE;
- p->serial_out(p, UART_MCR, mcr);
+ serial_port_out(p, UART_MCR, mcr);
}
serial8250_do_set_ldisc(p, termios);
}
@@ -406,6 +438,18 @@ static bool dw8250_idma_filter(struct dma_chan *chan, void *param)
return param == chan->device->dev;
}
+static void dw8250_setup_dma_filter(struct uart_port *p, struct dw8250_data *data)
+{
+ /* Platforms with iDMA 64-bit */
+ if (platform_get_resource_byname(to_platform_device(p->dev), IORESOURCE_MEM, "lpss_priv")) {
+ data->data.dma.rx_param = p->dev->parent;
+ data->data.dma.tx_param = p->dev->parent;
+ data->data.dma.fn = dw8250_idma_filter;
+ } else {
+ data->data.dma.fn = dw8250_fallback_dma_filter;
+ }
+}
+
static u32 dw8250_rzn1_get_dmacr_burst(int max_burst)
{
if (max_burst >= 8)
@@ -444,7 +488,11 @@ static void dw8250_prepare_rx_dma(struct uart_8250_port *p)
static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
{
- unsigned int quirks = data->pdata ? data->pdata->quirks : 0;
+ unsigned int quirks = data->pdata->quirks;
+ u32 cpr_value = data->pdata->cpr_value;
+
+ if (quirks & DW_UART_QUIRK_CPR_VALUE)
+ data->data.cpr_value = cpr_value;
#ifdef CONFIG_64BIT
if (quirks & DW_UART_QUIRK_OCTEON) {
@@ -472,14 +520,6 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data)
p->serial_in = dw8250_serial_in32;
data->uart_16550_compatible = true;
}
-
- /* Platforms with iDMA 64-bit */
- if (platform_get_resource_byname(to_platform_device(p->dev),
- IORESOURCE_MEM, "lpss_priv")) {
- data->data.dma.rx_param = p->dev->parent;
- data->data.dma.tx_param = p->dev->parent;
- data->data.dma.fn = dw8250_idma_filter;
- }
}
static void dw8250_reset_control_assert(void *data)
@@ -501,7 +541,6 @@ static int dw8250_probe(struct platform_device *pdev)
return dev_err_probe(dev, -EINVAL, "no registers defined\n");
spin_lock_init(&p->lock);
- p->handle_irq = dw8250_handle_irq;
p->pm = dw8250_do_pm;
p->type = PORT_8250;
p->flags = UPF_FIXED_PORT;
@@ -513,13 +552,8 @@ static int dw8250_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
- data->data.dma.fn = dw8250_fallback_dma_filter;
- data->pdata = device_get_match_data(p->dev);
p->private_data = &data->data;
- data->uart_16550_compatible = device_property_read_bool(dev,
- "snps,uart-16550-compatible");
-
p->mapbase = regs->start;
p->mapsize = resource_size(regs);
@@ -597,7 +631,7 @@ static int dw8250_probe(struct platform_device *pdev)
if (IS_ERR(data->pclk))
return PTR_ERR(data->pclk);
- data->rst = devm_reset_control_get_optional_exclusive(dev, NULL);
+ data->rst = devm_reset_control_array_get_optional_exclusive(dev);
if (IS_ERR(data->rst))
return PTR_ERR(data->rst);
@@ -607,11 +641,19 @@ static int dw8250_probe(struct platform_device *pdev)
if (err)
return err;
- dw8250_quirks(p, data);
+ data->uart_16550_compatible = device_property_read_bool(dev, "snps,uart-16550-compatible");
+
+ data->pdata = device_get_match_data(p->dev);
+ if (data->pdata)
+ dw8250_quirks(p, data);
/* If the Busy Functionality is not implemented, don't handle it */
if (data->uart_16550_compatible)
p->handle_irq = NULL;
+ else if (data->pdata)
+ p->handle_irq = dw8250_handle_irq;
+
+ dw8250_setup_dma_filter(p, data);
if (!data->skip_autocfg)
dw8250_setup_port(p);
@@ -727,11 +769,11 @@ static const struct dw8250_platform_data dw8250_armada_38x_data = {
static const struct dw8250_platform_data dw8250_renesas_rzn1_data = {
.usr_reg = DW_UART_USR,
- .cpr_val = 0x00012f32,
- .quirks = DW_UART_QUIRK_IS_DMA_FC,
+ .cpr_value = 0x00012f32,
+ .quirks = DW_UART_QUIRK_CPR_VALUE | DW_UART_QUIRK_IS_DMA_FC,
};
-static const struct dw8250_platform_data dw8250_starfive_jh7100_data = {
+static const struct dw8250_platform_data dw8250_skip_set_rate_data = {
.usr_reg = DW_UART_USR,
.quirks = DW_UART_QUIRK_SKIP_SET_RATE,
};
@@ -741,7 +783,8 @@ static const struct of_device_id dw8250_of_match[] = {
{ .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
{ .compatible = "marvell,armada-38x-uart", .data = &dw8250_armada_38x_data },
{ .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data },
- { .compatible = "starfive,jh7100-uart", .data = &dw8250_starfive_jh7100_data },
+ { .compatible = "sophgo,sg2044-uart", .data = &dw8250_skip_set_rate_data },
+ { .compatible = "starfive,jh7100-uart", .data = &dw8250_skip_set_rate_data },
{ /* Sentinel */ }
};
MODULE_DEVICE_TABLE(of, dw8250_of_match);
@@ -777,7 +820,7 @@ static struct platform_driver dw8250_platform_driver = {
.acpi_match_table = dw8250_acpi_match,
},
.probe = dw8250_probe,
- .remove_new = dw8250_remove,
+ .remove = dw8250_remove,
};
module_platform_driver(dw8250_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_dwlib.c b/drivers/tty/serial/8250/8250_dwlib.c
index 3e33ddf7bc80..b055d89cfb39 100644
--- a/drivers/tty/serial/8250/8250_dwlib.c
+++ b/drivers/tty/serial/8250/8250_dwlib.c
@@ -89,7 +89,7 @@ static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,
unsigned int quot, unsigned int quot_frac)
{
dw8250_writel_ext(p, DW_UART_DLF, quot_frac);
- serial8250_do_set_divisor(p, baud, quot, quot_frac);
+ serial8250_do_set_divisor(p, baud, quot);
}
void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios,
@@ -242,7 +242,6 @@ static const struct serial_rs485 dw8250_rs485_supported = {
void dw8250_setup_port(struct uart_port *p)
{
struct dw8250_port_data *pd = p->private_data;
- struct dw8250_data *data = to_dw8250_data(pd);
struct uart_8250_port *up = up_to_u8250p(p);
u32 reg, old_dlf;
@@ -278,7 +277,7 @@ void dw8250_setup_port(struct uart_port *p)
reg = dw8250_readl_ext(p, DW_UART_CPR);
if (!reg) {
- reg = data->pdata->cpr_val;
+ reg = pd->cpr_value;
dev_dbg(p->dev, "CPR is not available, using 0x%08x instead\n", reg);
}
if (!reg)
diff --git a/drivers/tty/serial/8250/8250_dwlib.h b/drivers/tty/serial/8250/8250_dwlib.h
index f13e91f2cace..7dd2a8e7b780 100644
--- a/drivers/tty/serial/8250/8250_dwlib.h
+++ b/drivers/tty/serial/8250/8250_dwlib.h
@@ -2,15 +2,10 @@
/* Synopsys DesignWare 8250 library header file. */
#include <linux/io.h>
-#include <linux/notifier.h>
#include <linux/types.h>
-#include <linux/workqueue.h>
#include "8250.h"
-struct clk;
-struct reset_control;
-
struct dw8250_port_data {
/* Port properties */
int line;
@@ -19,42 +14,16 @@ struct dw8250_port_data {
struct uart_8250_dma dma;
/* Hardware configuration */
+ u32 cpr_value;
u8 dlf_size;
/* RS485 variables */
bool hw_rs485_support;
};
-struct dw8250_platform_data {
- u8 usr_reg;
- u32 cpr_val;
- unsigned int quirks;
-};
-
-struct dw8250_data {
- struct dw8250_port_data data;
- const struct dw8250_platform_data *pdata;
-
- int msr_mask_on;
- int msr_mask_off;
- struct clk *clk;
- struct clk *pclk;
- struct notifier_block clk_notifier;
- struct work_struct clk_work;
- struct reset_control *rst;
-
- unsigned int skip_autocfg:1;
- unsigned int uart_16550_compatible:1;
-};
-
void dw8250_do_set_termios(struct uart_port *p, struct ktermios *termios, const struct ktermios *old);
void dw8250_setup_port(struct uart_port *p);
-static inline struct dw8250_data *to_dw8250_data(struct dw8250_port_data *data)
-{
- return container_of(data, struct dw8250_data, data);
-}
-
static inline u32 dw8250_readl_ext(struct uart_port *p, int offset)
{
if (p->iotype == UPIO_MEM32BE)
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index e3f482fd3de4..842422921765 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -46,8 +46,10 @@ static unsigned int serial8250_early_in(struct uart_port *port, int offset)
return readl(port->membase + offset);
case UPIO_MEM32BE:
return ioread32be(port->membase + offset);
+#ifdef CONFIG_HAS_IOPORT
case UPIO_PORT:
return inb(port->iobase + offset);
+#endif
default:
return 0;
}
@@ -70,9 +72,11 @@ static void serial8250_early_out(struct uart_port *port, int offset, int value)
case UPIO_MEM32BE:
iowrite32be(value, port->membase + offset);
break;
+#ifdef CONFIG_HAS_IOPORT
case UPIO_PORT:
outb(value, port->iobase + offset);
break;
+#endif
}
}
@@ -171,6 +175,17 @@ OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup);
OF_EARLYCON_DECLARE(uart, "nvidia,tegra20-uart", early_serial8250_setup);
OF_EARLYCON_DECLARE(uart, "snps,dw-apb-uart", early_serial8250_setup);
+static int __init early_serial8250_rs2_setup(struct earlycon_device *device,
+ const char *options)
+{
+ device->port.regshift = 2;
+
+ return early_serial8250_setup(device, options);
+}
+OF_EARLYCON_DECLARE(uart, "intel,xscale-uart", early_serial8250_rs2_setup);
+OF_EARLYCON_DECLARE(uart, "mrvl,mmp-uart", early_serial8250_rs2_setup);
+OF_EARLYCON_DECLARE(uart, "mrvl,pxa-uart", early_serial8250_rs2_setup);
+
#ifdef CONFIG_SERIAL_8250_OMAP
static int __init early_omap8250_setup(struct earlycon_device *device,
diff --git a/drivers/tty/serial/8250/8250_em.c b/drivers/tty/serial/8250/8250_em.c
index a754755100ff..35094f884492 100644
--- a/drivers/tty/serial/8250/8250_em.c
+++ b/drivers/tty/serial/8250/8250_em.c
@@ -219,7 +219,7 @@ static struct platform_driver serial8250_em_platform_driver = {
.of_match_table = serial8250_em_dt_ids,
},
.probe = serial8250_em_probe,
- .remove_new = serial8250_em_remove,
+ .remove = serial8250_em_remove,
};
module_platform_driver(serial8250_em_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c
index 0440df7de1ed..04a0cbab02c2 100644
--- a/drivers/tty/serial/8250/8250_exar.c
+++ b/drivers/tty/serial/8250/8250_exar.c
@@ -6,10 +6,12 @@
*
* Copyright (C) 2017 Sudip Mukherjee, All Rights Reserved.
*/
+#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmi.h>
+#include <linux/eeprom_93cx6.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/math.h>
@@ -46,8 +48,50 @@
#define PCI_DEVICE_ID_COMMTECH_4228PCIE 0x0021
#define PCI_DEVICE_ID_COMMTECH_4222PCIE 0x0022
+#define PCI_VENDOR_ID_CONNECT_TECH 0x12c4
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_SP_OPTO 0x0340
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_SP_OPTO_A 0x0341
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_SP_OPTO_B 0x0342
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS 0x0350
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_A 0x0351
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_B 0x0352
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS 0x0353
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_A 0x0354
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_B 0x0355
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS_OPTO 0x0360
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_A 0x0361
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_B 0x0362
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP 0x0370
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_232 0x0371
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_485 0x0372
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_SP 0x0373
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_6_2_SP 0x0374
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_6_SP 0x0375
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_232_NS 0x0376
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_LEFT 0x0380
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_RIGHT 0x0381
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XP_OPTO 0x0382
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_XPRS_OPTO 0x0392
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP 0x03A0
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_232 0x03A1
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_485 0x03A2
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_232_NS 0x03A3
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XEG001 0x0602
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_BASE 0x1000
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_2 0x1002
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_4 0x1004
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_8 0x1008
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_12 0x100C
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCIE_XR35X_16 0x1010
+#define PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG00X 0x110c
+#define PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG01X 0x110d
+#define PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_16 0x1110
+
#define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358
#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358
+#define PCI_DEVICE_ID_EXAR_XR17V252 0x0252
+#define PCI_DEVICE_ID_EXAR_XR17V254 0x0254
+#define PCI_DEVICE_ID_EXAR_XR17V258 0x0258
#define PCI_SUBDEVICE_ID_USR_2980 0x0128
#define PCI_SUBDEVICE_ID_USR_2981 0x0129
@@ -86,12 +130,23 @@
#define UART_EXAR_DLD 0x02 /* Divisor Fractional */
#define UART_EXAR_DLD_485_POLARITY 0x80 /* RS-485 Enable Signal Polarity */
+/* EEPROM registers */
+#define UART_EXAR_REGB 0x8e
+#define UART_EXAR_REGB_EECK BIT(4)
+#define UART_EXAR_REGB_EECS BIT(5)
+#define UART_EXAR_REGB_EEDI BIT(6)
+#define UART_EXAR_REGB_EEDO BIT(7)
+
+#define UART_EXAR_XR17C15X_PORT_OFFSET 0x200
+#define UART_EXAR_XR17V25X_PORT_OFFSET 0x200
+#define UART_EXAR_XR17V35X_PORT_OFFSET 0x400
+
/*
* IOT2040 MPIO wiring semantics:
*
* MPIO Port Function
* ---- ---- --------
- * 0 2 Mode bit 0
+ * 0 2 Mode bit 0
* 1 2 Mode bit 1
* 2 2 Terminate bus
* 3 - <reserved>
@@ -121,38 +176,247 @@
#define IOT2040_UARTS_ENABLE 0x03
#define IOT2040_UARTS_GPIO_HI_MODE 0xF8 /* enable & LED as outputs */
+/* CTI EEPROM offsets */
+#define CTI_EE_OFF_XR17C15X_OSC_FREQ 0x04 /* 2 words */
+#define CTI_EE_OFF_XR17C15X_PART_NUM 0x0A /* 4 words */
+#define CTI_EE_OFF_XR17C15X_SERIAL_NUM 0x0E /* 1 word */
+
+#define CTI_EE_OFF_XR17V25X_OSC_FREQ 0x08 /* 2 words */
+#define CTI_EE_OFF_XR17V25X_PART_NUM 0x0E /* 4 words */
+#define CTI_EE_OFF_XR17V25X_SERIAL_NUM 0x12 /* 1 word */
+
+#define CTI_EE_OFF_XR17V35X_SERIAL_NUM 0x11 /* 2 word */
+#define CTI_EE_OFF_XR17V35X_BRD_FLAGS 0x13 /* 1 word */
+#define CTI_EE_OFF_XR17V35X_PORT_FLAGS 0x14 /* 1 word */
+
+#define CTI_EE_MASK_PORT_FLAGS_TYPE GENMASK(7, 0)
+#define CTI_EE_MASK_OSC_FREQ GENMASK(31, 0)
+
+#define CTI_FPGA_RS485_IO_REG 0x2008
+#define CTI_FPGA_CFG_INT_EN_REG 0x48
+#define CTI_FPGA_CFG_INT_EN_EXT_BIT BIT(15) /* External int enable bit */
+
+#define CTI_DEFAULT_PCI_OSC_FREQ 29491200
+#define CTI_DEFAULT_PCIE_OSC_FREQ 125000000
+#define CTI_DEFAULT_FPGA_OSC_FREQ 33333333
+
+/*
+ * CTI Serial port line types. These match the values stored in the first
+ * nibble of the CTI EEPROM port_flags word.
+ */
+enum cti_port_type {
+ CTI_PORT_TYPE_NONE = 0,
+ CTI_PORT_TYPE_RS232, // RS232 ONLY
+ CTI_PORT_TYPE_RS422_485, // RS422/RS485 ONLY
+ CTI_PORT_TYPE_RS232_422_485_HW, // RS232/422/485 HW ONLY Switchable
+ CTI_PORT_TYPE_RS232_422_485_SW, // RS232/422/485 SW ONLY Switchable
+ CTI_PORT_TYPE_RS232_422_485_4B, // RS232/422/485 HW/SW (4bit ex. BCG004)
+ CTI_PORT_TYPE_RS232_422_485_2B, // RS232/422/485 HW/SW (2bit ex. BBG008)
+ CTI_PORT_TYPE_MAX,
+};
+
+#define CTI_PORT_TYPE_VALID(_port_type) \
+ (((_port_type) > CTI_PORT_TYPE_NONE) && \
+ ((_port_type) < CTI_PORT_TYPE_MAX))
+
+#define CTI_PORT_TYPE_RS485(_port_type) \
+ (((_port_type) > CTI_PORT_TYPE_RS232) && \
+ ((_port_type) < CTI_PORT_TYPE_MAX))
+
struct exar8250;
struct exar8250_platform {
int (*rs485_config)(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485);
const struct serial_rs485 *rs485_supported;
- int (*register_gpio)(struct pci_dev *, struct uart_8250_port *);
- void (*unregister_gpio)(struct uart_8250_port *);
+ int (*register_gpio)(struct pci_dev *pcidev, struct uart_8250_port *port);
+ void (*unregister_gpio)(struct uart_8250_port *port);
};
/**
* struct exar8250_board - board information
* @num_ports: number of serial ports
* @reg_shift: describes UART register mapping in PCI memory
- * @setup: quirk run at ->probe() stage
+ * @setup: quirk run at ->probe() stage for each port
* @exit: quirk run at ->remove() stage
*/
struct exar8250_board {
unsigned int num_ports;
unsigned int reg_shift;
- int (*setup)(struct exar8250 *, struct pci_dev *,
- struct uart_8250_port *, int);
+ int (*setup)(struct exar8250 *priv, struct pci_dev *pcidev,
+ struct uart_8250_port *port, int idx);
void (*exit)(struct pci_dev *pcidev);
};
struct exar8250 {
unsigned int nr;
+ unsigned int osc_freq;
struct exar8250_board *board;
+ struct eeprom_93cx6 eeprom;
void __iomem *virt;
int line[];
};
+static inline void exar_write_reg(struct exar8250 *priv,
+ unsigned int reg, u8 value)
+{
+ writeb(value, priv->virt + reg);
+}
+
+static inline u8 exar_read_reg(struct exar8250 *priv, unsigned int reg)
+{
+ return readb(priv->virt + reg);
+}
+
+static void exar_eeprom_93cx6_reg_read(struct eeprom_93cx6 *eeprom)
+{
+ struct exar8250 *priv = eeprom->data;
+ u8 regb = exar_read_reg(priv, UART_EXAR_REGB);
+
+ /* EECK and EECS always read 0 from REGB so only set EEDO */
+ eeprom->reg_data_out = regb & UART_EXAR_REGB_EEDO;
+}
+
+static void exar_eeprom_93cx6_reg_write(struct eeprom_93cx6 *eeprom)
+{
+ struct exar8250 *priv = eeprom->data;
+ u8 regb = 0;
+
+ if (eeprom->reg_data_in)
+ regb |= UART_EXAR_REGB_EEDI;
+ if (eeprom->reg_data_clock)
+ regb |= UART_EXAR_REGB_EECK;
+ if (eeprom->reg_chip_select)
+ regb |= UART_EXAR_REGB_EECS;
+
+ exar_write_reg(priv, UART_EXAR_REGB, regb);
+}
+
+static void exar_eeprom_init(struct exar8250 *priv)
+{
+ priv->eeprom.data = priv;
+ priv->eeprom.register_read = exar_eeprom_93cx6_reg_read;
+ priv->eeprom.register_write = exar_eeprom_93cx6_reg_write;
+ priv->eeprom.width = PCI_EEPROM_WIDTH_93C46;
+ priv->eeprom.quirks |= PCI_EEPROM_QUIRK_EXTRA_READ_CYCLE;
+}
+
+/**
+ * exar_mpio_config_output() - Configure an Exar MPIO as an output
+ * @priv: Device's private structure
+ * @mpio_num: MPIO number/offset to configure
+ *
+ * Configure a single MPIO as an output and disable tristate. It is recommended
+ * to set the level with exar_mpio_set_high()/exar_mpio_set_low() prior to
+ * calling this function to ensure default MPIO pin state.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int exar_mpio_config_output(struct exar8250 *priv,
+ unsigned int mpio_num)
+{
+ unsigned int mpio_offset;
+ u8 sel_reg; // MPIO Select register (input/output)
+ u8 tri_reg; // MPIO Tristate register
+ u8 value;
+
+ if (mpio_num < 8) {
+ sel_reg = UART_EXAR_MPIOSEL_7_0;
+ tri_reg = UART_EXAR_MPIO3T_7_0;
+ mpio_offset = mpio_num;
+ } else if (mpio_num >= 8 && mpio_num < 16) {
+ sel_reg = UART_EXAR_MPIOSEL_15_8;
+ tri_reg = UART_EXAR_MPIO3T_15_8;
+ mpio_offset = mpio_num - 8;
+ } else {
+ return -EINVAL;
+ }
+
+ // Disable MPIO pin tri-state
+ value = exar_read_reg(priv, tri_reg);
+ value &= ~BIT(mpio_offset);
+ exar_write_reg(priv, tri_reg, value);
+
+ value = exar_read_reg(priv, sel_reg);
+ value &= ~BIT(mpio_offset);
+ exar_write_reg(priv, sel_reg, value);
+
+ return 0;
+}
+
+/**
+ * _exar_mpio_set() - Set an Exar MPIO output high or low
+ * @priv: Device's private structure
+ * @mpio_num: MPIO number/offset to set
+ * @high: Set MPIO high if true, low if false
+ *
+ * Set a single MPIO high or low. exar_mpio_config_output() must also be called
+ * to configure the pin as an output.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int _exar_mpio_set(struct exar8250 *priv,
+ unsigned int mpio_num, bool high)
+{
+ unsigned int mpio_offset;
+ u8 lvl_reg;
+ u8 value;
+
+ if (mpio_num < 8) {
+ lvl_reg = UART_EXAR_MPIOLVL_7_0;
+ mpio_offset = mpio_num;
+ } else if (mpio_num >= 8 && mpio_num < 16) {
+ lvl_reg = UART_EXAR_MPIOLVL_15_8;
+ mpio_offset = mpio_num - 8;
+ } else {
+ return -EINVAL;
+ }
+
+ value = exar_read_reg(priv, lvl_reg);
+ if (high)
+ value |= BIT(mpio_offset);
+ else
+ value &= ~BIT(mpio_offset);
+ exar_write_reg(priv, lvl_reg, value);
+
+ return 0;
+}
+
+static int exar_mpio_set_low(struct exar8250 *priv, unsigned int mpio_num)
+{
+ return _exar_mpio_set(priv, mpio_num, false);
+}
+
+static int exar_mpio_set_high(struct exar8250 *priv, unsigned int mpio_num)
+{
+ return _exar_mpio_set(priv, mpio_num, true);
+}
+
+static int generic_rs485_config(struct uart_port *port, struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED);
+ u8 __iomem *p = port->membase;
+ u8 value;
+
+ value = readb(p + UART_EXAR_FCTR);
+ if (is_rs485)
+ value |= UART_FCTR_EXAR_485;
+ else
+ value &= ~UART_FCTR_EXAR_485;
+
+ writeb(value, p + UART_EXAR_FCTR);
+
+ if (is_rs485)
+ writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR);
+
+ return 0;
+}
+
+static const struct serial_rs485 generic_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND,
+};
+
static void exar_pm(struct uart_port *port, unsigned int state, unsigned int old)
{
/*
@@ -182,7 +446,7 @@ static unsigned int xr17v35x_get_divisor(struct uart_port *p, unsigned int baud,
static void xr17v35x_set_divisor(struct uart_port *p, unsigned int baud,
unsigned int quot, unsigned int quot_frac)
{
- serial8250_do_set_divisor(p, baud, quot, quot_frac);
+ serial8250_do_set_divisor(p, baud, quot);
/* Preserve bits not related to baudrate; DLD[7:4]. */
quot_frac |= serial_port_in(p, 0x2) & 0xf0;
@@ -198,7 +462,7 @@ static int xr17v35x_startup(struct uart_port *port)
serial_port_out(port, UART_XR_EFR, UART_EFR_ECB);
/*
- * Make sure all interrups are masked until initialization is
+ * Make sure all interrupts are masked until initialization is
* complete and the FIFOs are cleared
*
* Synchronize UART_IER access against the console.
@@ -214,7 +478,7 @@ static void exar_shutdown(struct uart_port *port)
{
bool tx_complete = false;
struct uart_8250_port *up = up_to_u8250p(port);
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
int i = 0;
u16 lsr;
@@ -225,7 +489,8 @@ static void exar_shutdown(struct uart_port *port)
else
tx_complete = false;
usleep_range(1000, 1100);
- } while (!uart_circ_empty(xmit) && !tx_complete && i++ < 1000);
+ } while (!kfifo_is_empty(&tport->xmit_fifo) &&
+ !tx_complete && i++ < 1000);
serial8250_do_shutdown(port);
}
@@ -289,41 +554,542 @@ pci_fastcom335_setup(struct exar8250 *priv, struct pci_dev *pcidev,
writeb(32, p + UART_EXAR_TXTRG);
writeb(32, p + UART_EXAR_RXTRG);
+ /* Skip the initial (per device) setup */
+ if (idx)
+ return 0;
+
/*
* Setup Multipurpose Input/Output pins.
*/
+ switch (pcidev->device) {
+ case PCI_DEVICE_ID_COMMTECH_4222PCI335:
+ case PCI_DEVICE_ID_COMMTECH_4224PCI335:
+ writeb(0x78, p + UART_EXAR_MPIOLVL_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
+ break;
+ case PCI_DEVICE_ID_COMMTECH_2324PCI335:
+ case PCI_DEVICE_ID_COMMTECH_2328PCI335:
+ writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
+ writeb(0xc0, p + UART_EXAR_MPIOINV_7_0);
+ writeb(0xc0, p + UART_EXAR_MPIOSEL_7_0);
+ break;
+ default:
+ break;
+ }
+ writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
+ writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
+ writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
+
+ return 0;
+}
+
+/**
+ * cti_tristate_disable() - Disable RS485 transciever tristate
+ * @priv: Device's private structure
+ * @port_num: Port number to set tristate off
+ *
+ * Most RS485 capable cards have a power on tristate jumper/switch that ensures
+ * the RS422/RS485 transceiver does not drive a multi-drop RS485 bus when it is
+ * not the master. When this jumper is installed the user must set the RS485
+ * mode to Full or Half duplex to disable tristate prior to using the port.
+ *
+ * Some Exar UARTs have an auto-tristate feature while others require setting
+ * an MPIO to disable the tristate.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int cti_tristate_disable(struct exar8250 *priv, unsigned int port_num)
+{
+ int ret;
+
+ ret = exar_mpio_set_high(priv, port_num);
+ if (ret)
+ return ret;
+
+ return exar_mpio_config_output(priv, port_num);
+}
+
+/**
+ * cti_plx_int_enable() - Enable UART interrupts to PLX bridge
+ * @priv: Device's private structure
+ *
+ * Some older CTI cards require MPIO_0 to be set low to enable the
+ * interrupts from the UART to the PLX PCI->PCIe bridge.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int cti_plx_int_enable(struct exar8250 *priv)
+{
+ int ret;
+
+ ret = exar_mpio_set_low(priv, 0);
+ if (ret)
+ return ret;
+
+ return exar_mpio_config_output(priv, 0);
+}
+
+/**
+ * cti_read_osc_freq() - Read the UART oscillator frequency from EEPROM
+ * @priv: Device's private structure
+ * @eeprom_offset: Offset where the oscillator frequency is stored
+ *
+ * CTI XR17x15X and XR17V25X cards have the serial boards oscillator frequency
+ * stored in the EEPROM. FPGA and XR17V35X based cards use the PCI/PCIe clock.
+ *
+ * Return: frequency on success, negative error code on failure
+ */
+static int cti_read_osc_freq(struct exar8250 *priv, u8 eeprom_offset)
+{
+ __le16 ee_words[2];
+ u32 osc_freq;
+
+ eeprom_93cx6_multiread(&priv->eeprom, eeprom_offset, ee_words, ARRAY_SIZE(ee_words));
+
+ osc_freq = le16_to_cpu(ee_words[0]) | (le16_to_cpu(ee_words[1]) << 16);
+ if (osc_freq == CTI_EE_MASK_OSC_FREQ)
+ return -EIO;
+
+ return osc_freq;
+}
+
+/**
+ * cti_get_port_type_xr17c15x_xr17v25x() - Get port type of xr17c15x/xr17v25x
+ * @priv: Device's private structure
+ * @pcidev: Pointer to the PCI device for this port
+ * @port_num: Port to get type of
+ *
+ * CTI xr17c15x and xr17v25x based cards port types are based on PCI IDs.
+ *
+ * Return: port type on success, CTI_PORT_TYPE_NONE on failure
+ */
+static enum cti_port_type cti_get_port_type_xr17c15x_xr17v25x(struct exar8250 *priv,
+ struct pci_dev *pcidev,
+ unsigned int port_num)
+{
+ switch (pcidev->subsystem_device) {
+ // RS232 only cards
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_232:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_232_NS:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_232:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_232_NS:
+ return CTI_PORT_TYPE_RS232;
+ // 1x RS232, 1x RS422/RS485
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1:
+ return (port_num == 0) ? CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485;
+ // 2x RS232, 2x RS422/RS485
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2:
+ return (port_num < 2) ? CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485;
+ // 4x RS232, 4x RS422/RS485
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_SP:
+ return (port_num < 4) ? CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485;
+ // RS232/RS422/RS485 HW (jumper) selectable
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_SP_OPTO:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_SP_OPTO_A:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_SP_OPTO_B:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_A:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_B:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_A:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_B:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS_OPTO:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_A:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_B:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_LEFT:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_RIGHT:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XP_OPTO:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_XPRS_OPTO:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP:
+ return CTI_PORT_TYPE_RS232_422_485_HW;
+ // RS422/RS485 HW (jumper) selectable
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_485:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_485:
+ return CTI_PORT_TYPE_RS422_485;
+ // 6x RS232, 2x RS422/RS485
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_6_2_SP:
+ return (port_num < 6) ? CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485;
+ // 2x RS232, 6x RS422/RS485
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_6_SP:
+ return (port_num < 2) ? CTI_PORT_TYPE_RS232 : CTI_PORT_TYPE_RS422_485;
+ default:
+ dev_err(&pcidev->dev, "unknown/unsupported device\n");
+ return CTI_PORT_TYPE_NONE;
+ }
+}
+
+/**
+ * cti_get_port_type_fpga() - Get the port type of a CTI FPGA card
+ * @priv: Device's private structure
+ * @pcidev: Pointer to the PCI device for this port
+ * @port_num: Port to get type of
+ *
+ * FPGA based cards port types are based on PCI IDs.
+ *
+ * Return: port type on success, CTI_PORT_TYPE_NONE on failure
+ */
+static enum cti_port_type cti_get_port_type_fpga(struct exar8250 *priv,
+ struct pci_dev *pcidev,
+ unsigned int port_num)
+{
+ switch (pcidev->device) {
+ case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG00X:
+ case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG01X:
+ case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_16:
+ return CTI_PORT_TYPE_RS232_422_485_HW;
+ default:
+ dev_err(&pcidev->dev, "unknown/unsupported device\n");
+ return CTI_PORT_TYPE_NONE;
+ }
+}
+
+/**
+ * cti_get_port_type_xr17v35x() - Read port type from the EEPROM
+ * @priv: Device's private structure
+ * @pcidev: Pointer to the PCI device for this port
+ * @port_num: port offset
+ *
+ * CTI XR17V35X based cards have the port types stored in the EEPROM.
+ * This function reads the port type for a single port.
+ *
+ * Return: port type on success, CTI_PORT_TYPE_NONE on failure
+ */
+static enum cti_port_type cti_get_port_type_xr17v35x(struct exar8250 *priv,
+ struct pci_dev *pcidev,
+ unsigned int port_num)
+{
+ enum cti_port_type port_type;
+ u16 port_flags;
+ u8 offset;
+
+ offset = CTI_EE_OFF_XR17V35X_PORT_FLAGS + port_num;
+ eeprom_93cx6_read(&priv->eeprom, offset, &port_flags);
+
+ port_type = FIELD_GET(CTI_EE_MASK_PORT_FLAGS_TYPE, port_flags);
+ if (CTI_PORT_TYPE_VALID(port_type))
+ return port_type;
+
+ /*
+ * If the port type is missing the card assume it is a
+ * RS232/RS422/RS485 card to be safe.
+ *
+ * There is one known board (BEG013) that only has 3 of 4 port types
+ * written to the EEPROM so this acts as a work around.
+ */
+ dev_warn(&pcidev->dev, "failed to get port %d type from EEPROM\n", port_num);
+
+ return CTI_PORT_TYPE_RS232_422_485_HW;
+}
+
+static int cti_rs485_config_mpio_tristate(struct uart_port *port,
+ struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ struct exar8250 *priv = (struct exar8250 *)port->private_data;
+ int ret;
+
+ ret = generic_rs485_config(port, termios, rs485);
+ if (ret)
+ return ret;
+
+ // Disable power-on RS485 tri-state via MPIO
+ return cti_tristate_disable(priv, port->port_id);
+}
+
+static void cti_board_init_osc_freq(struct exar8250 *priv, struct pci_dev *pcidev, u8 eeprom_offset)
+{
+ int osc_freq;
+
+ osc_freq = cti_read_osc_freq(priv, eeprom_offset);
+ if (osc_freq <= 0) {
+ dev_warn(&pcidev->dev, "failed to read OSC freq from EEPROM, using default\n");
+ osc_freq = CTI_DEFAULT_PCI_OSC_FREQ;
+ }
+
+ priv->osc_freq = osc_freq;
+}
+
+static int cti_port_setup_common(struct exar8250 *priv,
+ struct pci_dev *pcidev,
+ int idx, unsigned int offset,
+ struct uart_8250_port *port)
+{
+ int ret;
+
+ port->port.port_id = idx;
+ port->port.uartclk = priv->osc_freq;
+
+ ret = serial8250_pci_setup_port(pcidev, port, 0, offset, 0);
+ if (ret)
+ return ret;
+
+ port->port.private_data = (void *)priv;
+ port->port.pm = exar_pm;
+ port->port.shutdown = exar_shutdown;
+
+ return 0;
+}
+
+static int cti_board_init_fpga(struct exar8250 *priv, struct pci_dev *pcidev)
+{
+ int ret;
+ u16 cfg_val;
+
+ // FPGA OSC is fixed to the 33MHz PCI clock
+ priv->osc_freq = CTI_DEFAULT_FPGA_OSC_FREQ;
+
+ // Enable external interrupts in special cfg space register
+ ret = pci_read_config_word(pcidev, CTI_FPGA_CFG_INT_EN_REG, &cfg_val);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ cfg_val |= CTI_FPGA_CFG_INT_EN_EXT_BIT;
+ ret = pci_write_config_word(pcidev, CTI_FPGA_CFG_INT_EN_REG, cfg_val);
+ if (ret)
+ return pcibios_err_to_errno(ret);
+
+ // RS485 gate needs to be enabled; otherwise RTS/CTS will not work
+ exar_write_reg(priv, CTI_FPGA_RS485_IO_REG, 0x01);
+
+ return 0;
+}
+
+static int cti_port_setup_fpga(struct exar8250 *priv,
+ struct pci_dev *pcidev,
+ struct uart_8250_port *port,
+ int idx)
+{
+ enum cti_port_type port_type;
+ unsigned int offset;
+ int ret;
+
if (idx == 0) {
- switch (pcidev->device) {
- case PCI_DEVICE_ID_COMMTECH_4222PCI335:
- case PCI_DEVICE_ID_COMMTECH_4224PCI335:
- writeb(0x78, p + UART_EXAR_MPIOLVL_7_0);
- writeb(0x00, p + UART_EXAR_MPIOINV_7_0);
- writeb(0x00, p + UART_EXAR_MPIOSEL_7_0);
+ ret = cti_board_init_fpga(priv, pcidev);
+ if (ret)
+ return ret;
+ }
+
+ port_type = cti_get_port_type_fpga(priv, pcidev, idx);
+
+ // FPGA shares port offsets with XR17C15X
+ offset = idx * UART_EXAR_XR17C15X_PORT_OFFSET;
+ port->port.type = PORT_XR17D15X;
+
+ port->port.get_divisor = xr17v35x_get_divisor;
+ port->port.set_divisor = xr17v35x_set_divisor;
+ port->port.startup = xr17v35x_startup;
+
+ if (CTI_PORT_TYPE_RS485(port_type)) {
+ port->port.rs485_config = generic_rs485_config;
+ port->port.rs485_supported = generic_rs485_supported;
+ }
+
+ return cti_port_setup_common(priv, pcidev, idx, offset, port);
+}
+
+static void cti_board_init_xr17v35x(struct exar8250 *priv, struct pci_dev *pcidev)
+{
+ // XR17V35X uses the PCIe clock rather than an oscillator
+ priv->osc_freq = CTI_DEFAULT_PCIE_OSC_FREQ;
+}
+
+static int cti_port_setup_xr17v35x(struct exar8250 *priv,
+ struct pci_dev *pcidev,
+ struct uart_8250_port *port,
+ int idx)
+{
+ enum cti_port_type port_type;
+ unsigned int offset;
+ int ret;
+
+ if (idx == 0)
+ cti_board_init_xr17v35x(priv, pcidev);
+
+ port_type = cti_get_port_type_xr17v35x(priv, pcidev, idx);
+
+ offset = idx * UART_EXAR_XR17V35X_PORT_OFFSET;
+ port->port.type = PORT_XR17V35X;
+
+ port->port.get_divisor = xr17v35x_get_divisor;
+ port->port.set_divisor = xr17v35x_set_divisor;
+ port->port.startup = xr17v35x_startup;
+
+ switch (port_type) {
+ case CTI_PORT_TYPE_RS422_485:
+ case CTI_PORT_TYPE_RS232_422_485_HW:
+ port->port.rs485_config = cti_rs485_config_mpio_tristate;
+ port->port.rs485_supported = generic_rs485_supported;
+ break;
+ case CTI_PORT_TYPE_RS232_422_485_SW:
+ case CTI_PORT_TYPE_RS232_422_485_4B:
+ case CTI_PORT_TYPE_RS232_422_485_2B:
+ port->port.rs485_config = generic_rs485_config;
+ port->port.rs485_supported = generic_rs485_supported;
+ break;
+ default:
+ break;
+ }
+
+ ret = cti_port_setup_common(priv, pcidev, idx, offset, port);
+ if (ret)
+ return ret;
+
+ exar_write_reg(priv, (offset + UART_EXAR_8XMODE), 0x00);
+ exar_write_reg(priv, (offset + UART_EXAR_FCTR), UART_FCTR_EXAR_TRGD);
+ exar_write_reg(priv, (offset + UART_EXAR_TXTRG), 128);
+ exar_write_reg(priv, (offset + UART_EXAR_RXTRG), 128);
+
+ return 0;
+}
+
+static void cti_board_init_xr17v25x(struct exar8250 *priv, struct pci_dev *pcidev)
+{
+ cti_board_init_osc_freq(priv, pcidev, CTI_EE_OFF_XR17V25X_OSC_FREQ);
+
+ /* enable interrupts on cards that need the "PLX fix" */
+ switch (pcidev->subsystem_device) {
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_A:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_16_XPRS_B:
+ cti_plx_int_enable(priv);
+ break;
+ default:
+ break;
+ }
+}
+
+static int cti_port_setup_xr17v25x(struct exar8250 *priv,
+ struct pci_dev *pcidev,
+ struct uart_8250_port *port,
+ int idx)
+{
+ enum cti_port_type port_type;
+ unsigned int offset;
+ int ret;
+
+ if (idx == 0)
+ cti_board_init_xr17v25x(priv, pcidev);
+
+ port_type = cti_get_port_type_xr17c15x_xr17v25x(priv, pcidev, idx);
+
+ offset = idx * UART_EXAR_XR17V25X_PORT_OFFSET;
+ port->port.type = PORT_XR17D15X;
+
+ // XR17V25X supports fractional baudrates
+ port->port.get_divisor = xr17v35x_get_divisor;
+ port->port.set_divisor = xr17v35x_set_divisor;
+ port->port.startup = xr17v35x_startup;
+
+ if (CTI_PORT_TYPE_RS485(port_type)) {
+ switch (pcidev->subsystem_device) {
+ // These cards support power on 485 tri-state via MPIO
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_485:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_SP:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_6_2_SP:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_6_SP:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_LEFT:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_RIGHT:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XP_OPTO:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_XPRS_OPTO:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_485:
+ port->port.rs485_config = cti_rs485_config_mpio_tristate;
break;
- case PCI_DEVICE_ID_COMMTECH_2324PCI335:
- case PCI_DEVICE_ID_COMMTECH_2328PCI335:
- writeb(0x00, p + UART_EXAR_MPIOLVL_7_0);
- writeb(0xc0, p + UART_EXAR_MPIOINV_7_0);
- writeb(0xc0, p + UART_EXAR_MPIOSEL_7_0);
+ // Otherwise auto or no power on 485 tri-state support
+ default:
+ port->port.rs485_config = generic_rs485_config;
break;
}
- writeb(0x00, p + UART_EXAR_MPIOINT_7_0);
- writeb(0x00, p + UART_EXAR_MPIO3T_7_0);
- writeb(0x00, p + UART_EXAR_MPIOOD_7_0);
+
+ port->port.rs485_supported = generic_rs485_supported;
}
+ ret = cti_port_setup_common(priv, pcidev, idx, offset, port);
+ if (ret)
+ return ret;
+
+ exar_write_reg(priv, (offset + UART_EXAR_8XMODE), 0x00);
+ exar_write_reg(priv, (offset + UART_EXAR_FCTR), UART_FCTR_EXAR_TRGD);
+ exar_write_reg(priv, (offset + UART_EXAR_TXTRG), 32);
+ exar_write_reg(priv, (offset + UART_EXAR_RXTRG), 32);
+
return 0;
}
-static int
-pci_connect_tech_setup(struct exar8250 *priv, struct pci_dev *pcidev,
- struct uart_8250_port *port, int idx)
+static void cti_board_init_xr17c15x(struct exar8250 *priv, struct pci_dev *pcidev)
{
- unsigned int offset = idx * 0x200;
- unsigned int baud = 1843200;
+ cti_board_init_osc_freq(priv, pcidev, CTI_EE_OFF_XR17C15X_OSC_FREQ);
+
+ /* enable interrupts on cards that need the "PLX fix" */
+ switch (pcidev->subsystem_device) {
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_A:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_B:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XPRS_OPTO:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_A:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XPRS_OPTO_B:
+ cti_plx_int_enable(priv);
+ break;
+ default:
+ break;
+ }
+}
- port->port.uartclk = baud * 16;
- return default_setup(priv, pcidev, idx, offset, port);
+static int cti_port_setup_xr17c15x(struct exar8250 *priv,
+ struct pci_dev *pcidev,
+ struct uart_8250_port *port,
+ int idx)
+{
+ enum cti_port_type port_type;
+ unsigned int offset;
+
+ if (idx == 0)
+ cti_board_init_xr17c15x(priv, pcidev);
+
+ port_type = cti_get_port_type_xr17c15x_xr17v25x(priv, pcidev, idx);
+
+ offset = idx * UART_EXAR_XR17C15X_PORT_OFFSET;
+ port->port.type = PORT_XR17D15X;
+
+ if (CTI_PORT_TYPE_RS485(port_type)) {
+ switch (pcidev->subsystem_device) {
+ // These cards support power on 485 tri-state via MPIO
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_SP_485:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_SP:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_6_2_SP:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_6_SP:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_LEFT:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_XP_OPTO_RIGHT:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_XP_OPTO:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4_XPRS_OPTO:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP:
+ case PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_XPRS_LP_485:
+ port->port.rs485_config = cti_rs485_config_mpio_tristate;
+ break;
+ // Otherwise auto or no power on 485 tri-state support
+ default:
+ port->port.rs485_config = generic_rs485_config;
+ break;
+ }
+
+ port->port.rs485_supported = generic_rs485_supported;
+ }
+
+ return cti_port_setup_common(priv, pcidev, idx, offset, port);
}
static int
@@ -344,11 +1110,10 @@ static void setup_gpio(struct pci_dev *pcidev, u8 __iomem *p)
* devices will export them as GPIOs, so we pre-configure them safely
* as inputs.
*/
-
u8 dir = 0x00;
if ((pcidev->vendor == PCI_VENDOR_ID_EXAR) &&
- (pcidev->subsystem_vendor != PCI_VENDOR_ID_SEALEVEL)) {
+ (pcidev->subsystem_vendor != PCI_VENDOR_ID_SEALEVEL)) {
// Configure GPIO as inputs for Commtech adapters
dir = 0xff;
} else {
@@ -425,27 +1190,6 @@ static void xr17v35x_unregister_gpio(struct uart_8250_port *port)
port->port.private_data = NULL;
}
-static int generic_rs485_config(struct uart_port *port, struct ktermios *termios,
- struct serial_rs485 *rs485)
-{
- bool is_rs485 = !!(rs485->flags & SER_RS485_ENABLED);
- u8 __iomem *p = port->membase;
- u8 value;
-
- value = readb(p + UART_EXAR_FCTR);
- if (is_rs485)
- value |= UART_FCTR_EXAR_485;
- else
- value &= ~UART_FCTR_EXAR_485;
-
- writeb(value, p + UART_EXAR_FCTR);
-
- if (is_rs485)
- writeb(UART_EXAR_RS485_DLY(4), p + UART_MSR);
-
- return 0;
-}
-
static int sealevel_rs485_config(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485)
{
@@ -459,35 +1203,32 @@ static int sealevel_rs485_config(struct uart_port *port, struct ktermios *termio
if (ret)
return ret;
- if (rs485->flags & SER_RS485_ENABLED) {
- old_lcr = readb(p + UART_LCR);
+ if (!(rs485->flags & SER_RS485_ENABLED))
+ return 0;
- /* Set EFR[4]=1 to enable enhanced feature registers */
- efr = readb(p + UART_XR_EFR);
- efr |= UART_EFR_ECB;
- writeb(efr, p + UART_XR_EFR);
+ old_lcr = readb(p + UART_LCR);
- /* Set MCR to use DTR as Auto-RS485 Enable signal */
- writeb(UART_MCR_OUT1, p + UART_MCR);
+ /* Set EFR[4]=1 to enable enhanced feature registers */
+ efr = readb(p + UART_XR_EFR);
+ efr |= UART_EFR_ECB;
+ writeb(efr, p + UART_XR_EFR);
- /* Set LCR[7]=1 to enable access to DLD register */
- writeb(old_lcr | UART_LCR_DLAB, p + UART_LCR);
+ /* Set MCR to use DTR as Auto-RS485 Enable signal */
+ writeb(UART_MCR_OUT1, p + UART_MCR);
- /* Set DLD[7]=1 for inverted RS485 Enable logic */
- dld = readb(p + UART_EXAR_DLD);
- dld |= UART_EXAR_DLD_485_POLARITY;
- writeb(dld, p + UART_EXAR_DLD);
+ /* Set LCR[7]=1 to enable access to DLD register */
+ writeb(old_lcr | UART_LCR_DLAB, p + UART_LCR);
- writeb(old_lcr, p + UART_LCR);
- }
+ /* Set DLD[7]=1 for inverted RS485 Enable logic */
+ dld = readb(p + UART_EXAR_DLD);
+ dld |= UART_EXAR_DLD_485_POLARITY;
+ writeb(dld, p + UART_EXAR_DLD);
+
+ writeb(old_lcr, p + UART_LCR);
return 0;
}
-static const struct serial_rs485 generic_rs485_supported = {
- .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND,
-};
-
static const struct exar8250_platform exar8250_default_platform = {
.register_gpio = xr17v35x_register_gpio,
.unregister_gpio = xr17v35x_unregister_gpio,
@@ -672,6 +1413,35 @@ static irqreturn_t exar_misc_handler(int irq, void *data)
return IRQ_HANDLED;
}
+static unsigned int exar_get_nr_ports(struct exar8250_board *board, struct pci_dev *pcidev)
+{
+ if (pcidev->vendor == PCI_VENDOR_ID_ACCESSIO)
+ return BIT(((pcidev->device & 0x38) >> 3) - 1);
+
+ // Check if board struct overrides number of ports
+ if (board->num_ports > 0)
+ return board->num_ports;
+
+ // Exar encodes # ports in last nibble of PCI Device ID ex. 0358
+ if (pcidev->vendor == PCI_VENDOR_ID_EXAR)
+ return pcidev->device & 0x0f;
+
+ // Handle CTI FPGA cards
+ if (pcidev->vendor == PCI_VENDOR_ID_CONNECT_TECH) {
+ switch (pcidev->device) {
+ case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG00X:
+ case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_12_XIG01X:
+ return 12;
+ case PCI_DEVICE_ID_CONNECT_TECH_PCI_XR79X_16:
+ return 16;
+ default:
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
static int
exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
{
@@ -691,12 +1461,9 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
maxnr = pci_resource_len(pcidev, bar) >> (board->reg_shift + 3);
- if (pcidev->vendor == PCI_VENDOR_ID_ACCESSIO)
- nr_ports = BIT(((pcidev->device & 0x38) >> 3) - 1);
- else if (board->num_ports)
- nr_ports = board->num_ports;
- else
- nr_ports = pcidev->device & 0x0f;
+ nr_ports = exar_get_nr_ports(board, pcidev);
+ if (nr_ports == 0)
+ return dev_err_probe(&pcidev->dev, -ENODEV, "failed to get number of ports\n");
priv = devm_kzalloc(&pcidev->dev, struct_size(priv, line, nr_ports), GFP_KERNEL);
if (!priv)
@@ -726,10 +1493,12 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
if (rc)
return rc;
+ exar_eeprom_init(priv);
+
for (i = 0; i < nr_ports && i < maxnr; i++) {
rc = board->setup(priv, pcidev, &uart, i);
if (rc) {
- dev_err(&pcidev->dev, "Failed to setup port %u\n", i);
+ dev_err_probe(&pcidev->dev, rc, "Failed to setup port %u\n", i);
break;
}
@@ -738,10 +1507,9 @@ exar_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
priv->line[i] = serial8250_register_8250_port(&uart);
if (priv->line[i] < 0) {
- dev_err(&pcidev->dev,
- "Couldn't register serial port %lx, irq %d, type %d, error %d\n",
- uart.port.iobase, uart.port.irq,
- uart.port.iotype, priv->line[i]);
+ dev_err_probe(&pcidev->dev, priv->line[i],
+ "Couldn't register serial port %lx, type %d, irq %d\n",
+ uart.port.iobase, uart.port.iotype, uart.port.irq);
break;
}
}
@@ -806,8 +1574,20 @@ static const struct exar8250_board pbn_fastcom335_8 = {
.setup = pci_fastcom335_setup,
};
-static const struct exar8250_board pbn_connect = {
- .setup = pci_connect_tech_setup,
+static const struct exar8250_board pbn_cti_xr17c15x = {
+ .setup = cti_port_setup_xr17c15x,
+};
+
+static const struct exar8250_board pbn_cti_xr17v25x = {
+ .setup = cti_port_setup_xr17v25x,
+};
+
+static const struct exar8250_board pbn_cti_xr17v35x = {
+ .setup = cti_port_setup_xr17v35x,
+};
+
+static const struct exar8250_board pbn_cti_fpga = {
+ .setup = cti_port_setup_fpga,
};
static const struct exar8250_board pbn_exar_ibm_saturn = {
@@ -854,13 +1634,13 @@ static const struct exar8250_board pbn_exar_XR17V8358 = {
.exit = pci_xr17v35x_exit,
};
-#define CONNECT_DEVICE(devid, sdevid, bd) { \
- PCI_DEVICE_SUB( \
- PCI_VENDOR_ID_EXAR, \
- PCI_DEVICE_ID_EXAR_##devid, \
- PCI_SUBVENDOR_ID_CONNECT_TECH, \
- PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_##sdevid), 0, 0, \
- (kernel_ulong_t)&bd \
+#define CTI_EXAR_DEVICE(devid, bd) { \
+ PCI_DEVICE_SUB( \
+ PCI_VENDOR_ID_EXAR, \
+ PCI_DEVICE_ID_EXAR_##devid, \
+ PCI_SUBVENDOR_ID_CONNECT_TECH, \
+ PCI_ANY_ID), 0, 0, \
+ (kernel_ulong_t)&bd \
}
#define EXAR_DEVICE(vend, devid, bd) { PCI_DEVICE_DATA(vend, devid, &bd) }
@@ -869,7 +1649,7 @@ static const struct exar8250_board pbn_exar_XR17V8358 = {
PCI_DEVICE_SUB( \
PCI_VENDOR_ID_EXAR, \
PCI_DEVICE_ID_EXAR_##devid, \
- PCI_VENDOR_ID_IBM, \
+ PCI_SUBVENDOR_ID_IBM, \
PCI_SUBDEVICE_ID_IBM_##sdevid), 0, 0, \
(kernel_ulong_t)&bd \
}
@@ -892,18 +1672,23 @@ static const struct pci_device_id exar_pci_tbl[] = {
EXAR_DEVICE(ACCESSIO, COM_4SM, pbn_exar_XR17C15x),
EXAR_DEVICE(ACCESSIO, COM_8SM, pbn_exar_XR17C15x),
- CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect),
- CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect),
- CONNECT_DEVICE(XR17C158, UART_8_232, pbn_connect),
- CONNECT_DEVICE(XR17C152, UART_1_1, pbn_connect),
- CONNECT_DEVICE(XR17C154, UART_2_2, pbn_connect),
- CONNECT_DEVICE(XR17C158, UART_4_4, pbn_connect),
- CONNECT_DEVICE(XR17C152, UART_2, pbn_connect),
- CONNECT_DEVICE(XR17C154, UART_4, pbn_connect),
- CONNECT_DEVICE(XR17C158, UART_8, pbn_connect),
- CONNECT_DEVICE(XR17C152, UART_2_485, pbn_connect),
- CONNECT_DEVICE(XR17C154, UART_4_485, pbn_connect),
- CONNECT_DEVICE(XR17C158, UART_8_485, pbn_connect),
+ /* Connect Tech cards with Exar vendor/device PCI IDs */
+ CTI_EXAR_DEVICE(XR17C152, pbn_cti_xr17c15x),
+ CTI_EXAR_DEVICE(XR17C154, pbn_cti_xr17c15x),
+ CTI_EXAR_DEVICE(XR17C158, pbn_cti_xr17c15x),
+
+ CTI_EXAR_DEVICE(XR17V252, pbn_cti_xr17v25x),
+ CTI_EXAR_DEVICE(XR17V254, pbn_cti_xr17v25x),
+ CTI_EXAR_DEVICE(XR17V258, pbn_cti_xr17v25x),
+
+ CTI_EXAR_DEVICE(XR17V352, pbn_cti_xr17v35x),
+ CTI_EXAR_DEVICE(XR17V354, pbn_cti_xr17v35x),
+ CTI_EXAR_DEVICE(XR17V358, pbn_cti_xr17v35x),
+
+ /* Connect Tech cards with Connect Tech vendor/device PCI IDs (FPGA based) */
+ EXAR_DEVICE(CONNECT_TECH, PCI_XR79X_12_XIG00X, pbn_cti_fpga),
+ EXAR_DEVICE(CONNECT_TECH, PCI_XR79X_12_XIG01X, pbn_cti_fpga),
+ EXAR_DEVICE(CONNECT_TECH, PCI_XR79X_16, pbn_cti_fpga),
IBM_DEVICE(XR17C152, SATURN_SERIAL_ONE_PORT, pbn_exar_ibm_saturn),
@@ -945,7 +1730,7 @@ static struct pci_driver exar_pci_driver = {
};
module_pci_driver(exar_pci_driver);
-MODULE_IMPORT_NS(SERIAL_8250_PCI);
+MODULE_IMPORT_NS("SERIAL_8250_PCI");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Exar Serial Driver");
MODULE_AUTHOR("Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>");
diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c
index e2aa2a1a02dd..b4461a89b8d0 100644
--- a/drivers/tty/serial/8250/8250_fintek.c
+++ b/drivers/tty/serial/8250/8250_fintek.c
@@ -21,6 +21,7 @@
#define CHIP_ID_F81866 0x1010
#define CHIP_ID_F81966 0x0215
#define CHIP_ID_F81216AD 0x1602
+#define CHIP_ID_F81216E 0x1617
#define CHIP_ID_F81216H 0x0501
#define CHIP_ID_F81216 0x0802
#define VENDOR_ID1 0x23
@@ -125,7 +126,7 @@ static int fintek_8250_enter_key(u16 base_port, u8 key)
if (!request_muxed_region(base_port, 2, "8250_fintek"))
return -EBUSY;
- /* Force to deactive all SuperIO in this base_port */
+ /* Force to deactivate all SuperIO in this base_port */
outb(EXIT_KEY, base_port + ADDR_PORT);
outb(key, base_port + ADDR_PORT);
@@ -158,6 +159,7 @@ static int fintek_8250_check_id(struct fintek_8250 *pdata)
case CHIP_ID_F81866:
case CHIP_ID_F81966:
case CHIP_ID_F81216AD:
+ case CHIP_ID_F81216E:
case CHIP_ID_F81216H:
case CHIP_ID_F81216:
break;
@@ -181,6 +183,7 @@ static int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min,
return 0;
case CHIP_ID_F81216AD:
+ case CHIP_ID_F81216E:
case CHIP_ID_F81216H:
case CHIP_ID_F81216:
*min = F81216_LDN_LOW;
@@ -250,6 +253,7 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level)
break;
case CHIP_ID_F81216AD:
+ case CHIP_ID_F81216E:
case CHIP_ID_F81216H:
case CHIP_ID_F81216:
sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_SHARE,
@@ -263,7 +267,8 @@ static void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level)
static void fintek_8250_set_max_fifo(struct fintek_8250 *pdata)
{
switch (pdata->pid) {
- case CHIP_ID_F81216H: /* 128Bytes FIFO */
+ case CHIP_ID_F81216E: /* 128Bytes FIFO */
+ case CHIP_ID_F81216H:
case CHIP_ID_F81966:
case CHIP_ID_F81866:
sio_write_mask_reg(pdata, FIFO_CTRL,
@@ -297,6 +302,7 @@ static void fintek_8250_set_termios(struct uart_port *port,
goto exit;
switch (pdata->pid) {
+ case CHIP_ID_F81216E:
case CHIP_ID_F81216H:
reg = RS485;
break;
@@ -346,6 +352,7 @@ static void fintek_8250_set_termios_handler(struct uart_8250_port *uart)
struct fintek_8250 *pdata = uart->port.private_data;
switch (pdata->pid) {
+ case CHIP_ID_F81216E:
case CHIP_ID_F81216H:
case CHIP_ID_F81966:
case CHIP_ID_F81866:
@@ -438,6 +445,11 @@ static void fintek_8250_set_rs485_handler(struct uart_8250_port *uart)
uart->port.rs485_supported = fintek_8250_rs485_supported;
break;
+ case CHIP_ID_F81216E: /* F81216E does not support RS485 delays */
+ uart->port.rs485_config = fintek_8250_rs485_config;
+ uart->port.rs485_supported = fintek_8250_rs485_supported;
+ break;
+
default: /* No RS485 Auto direction functional */
break;
}
diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c
index b4ed442082a8..649ae5c8304d 100644
--- a/drivers/tty/serial/8250/8250_fsl.c
+++ b/drivers/tty/serial/8250/8250_fsl.c
@@ -32,7 +32,7 @@ int fsl8250_handle_irq(struct uart_port *port)
uart_port_lock_irqsave(&up->port, &flags);
- iir = port->serial_in(port, UART_IIR);
+ iir = serial_port_in(port, UART_IIR);
if (iir & UART_IIR_NO_INT) {
uart_port_unlock_irqrestore(&up->port, flags);
return 0;
@@ -54,12 +54,12 @@ int fsl8250_handle_irq(struct uart_port *port)
if (unlikely((iir & UART_IIR_ID) == UART_IIR_RLSI &&
(up->lsr_saved_flags & UART_LSR_BI))) {
up->lsr_saved_flags &= ~UART_LSR_BI;
- port->serial_in(port, UART_RX);
+ serial_port_in(port, UART_RX);
uart_port_unlock_irqrestore(&up->port, flags);
return 1;
}
- lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR);
+ lsr = orig_lsr = serial_port_in(port, UART_LSR);
/* Process incoming characters first */
if ((lsr & (UART_LSR_DR | UART_LSR_BI)) &&
@@ -71,7 +71,7 @@ int fsl8250_handle_irq(struct uart_port *port)
if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) {
unsigned long delay;
- up->ier = port->serial_in(port, UART_IER);
+ up->ier = serial_port_in(port, UART_IER);
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
port->ops->stop_rx(port);
} else {
@@ -179,7 +179,7 @@ static struct platform_driver fsl8250_platform_driver = {
.acpi_match_table = ACPI_PTR(fsl_8250_acpi_id),
},
.probe = fsl8250_acpi_probe,
- .remove_new = fsl8250_acpi_remove,
+ .remove = fsl8250_acpi_remove,
};
module_platform_driver(fsl8250_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c
index a2783e38a2e3..a73dd3773640 100644
--- a/drivers/tty/serial/8250/8250_ingenic.c
+++ b/drivers/tty/serial/8250/8250_ingenic.c
@@ -361,7 +361,7 @@ static struct platform_driver ingenic_uart_platform_driver = {
.of_match_table = of_match,
},
.probe = ingenic_uart_probe,
- .remove_new = ingenic_uart_remove,
+ .remove = ingenic_uart_remove,
};
module_platform_driver(ingenic_uart_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c
index 50c77c3dacf2..499e80aa4cf9 100644
--- a/drivers/tty/serial/8250/8250_ioc3.c
+++ b/drivers/tty/serial/8250/8250_ioc3.c
@@ -84,7 +84,7 @@ static void serial8250_ioc3_remove(struct platform_device *pdev)
static struct platform_driver serial8250_ioc3_driver = {
.probe = serial8250_ioc3_probe,
- .remove_new = serial8250_ioc3_remove,
+ .remove = serial8250_ioc3_remove,
.driver = {
.name = "ioc3-serial8250",
}
diff --git a/drivers/tty/serial/8250/8250_lpc18xx.c b/drivers/tty/serial/8250/8250_lpc18xx.c
index 47e1a056a60c..d52445948da0 100644
--- a/drivers/tty/serial/8250/8250_lpc18xx.c
+++ b/drivers/tty/serial/8250/8250_lpc18xx.c
@@ -195,7 +195,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_serial_match);
static struct platform_driver lpc18xx_serial_driver = {
.probe = lpc18xx_serial_probe,
- .remove_new = lpc18xx_serial_remove,
+ .remove = lpc18xx_serial_remove,
.driver = {
.name = "lpc18xx-uart",
.of_match_table = lpc18xx_serial_match,
diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c
index dc9e093b1cb3..a78ef35c8187 100644
--- a/drivers/tty/serial/8250/8250_men_mcb.c
+++ b/drivers/tty/serial/8250/8250_men_mcb.c
@@ -271,4 +271,4 @@ MODULE_AUTHOR("Michael Moese <michael.moese@men.de");
MODULE_ALIAS("mcb:16z125");
MODULE_ALIAS("mcb:16z025");
MODULE_ALIAS("mcb:16z057");
-MODULE_IMPORT_NS(MCB);
+MODULE_IMPORT_NS("MCB");
diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c
index 9ff6bbe9c086..b44de2ed7413 100644
--- a/drivers/tty/serial/8250/8250_mtk.c
+++ b/drivers/tty/serial/8250/8250_mtk.c
@@ -199,7 +199,7 @@ static int mtk8250_startup(struct uart_port *port)
if (up->dma) {
data->rx_status = DMA_RX_START;
- uart_circ_clear(&port->state->xmit);
+ kfifo_reset(&port->state->port.xmit_fifo);
}
#endif
memset(&port->icount, 0, sizeof(port->icount));
@@ -209,15 +209,19 @@ static int mtk8250_startup(struct uart_port *port)
static void mtk8250_shutdown(struct uart_port *port)
{
-#ifdef CONFIG_SERIAL_8250_DMA
struct uart_8250_port *up = up_to_u8250p(port);
struct mtk8250_data *data = port->private_data;
+ int irq = data->rx_wakeup_irq;
+#ifdef CONFIG_SERIAL_8250_DMA
if (up->dma)
data->rx_status = DMA_RX_SHUTDOWN;
#endif
- return serial8250_do_shutdown(port);
+ serial8250_do_shutdown(port);
+
+ if (irq >= 0)
+ serial8250_do_set_mctrl(&up->port, TIOCM_RTS);
}
static void mtk8250_disable_intrs(struct uart_8250_port *up, int mask)
@@ -342,8 +346,8 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios,
/*
* Mediatek UARTs use an extra highspeed register (MTK_UART_HIGHS)
*
- * We need to recalcualte the quot register, as the claculation depends
- * on the vaule in the highspeed register.
+ * We need to recalculate the quot register, as the calculation depends
+ * on the value in the highspeed register.
*
* Some baudrates are not supported by the chip, so we use the next
* lower rate supported and update termios c_flag.
@@ -650,7 +654,7 @@ static struct platform_driver mtk8250_platform_driver = {
.of_match_table = mtk8250_of_match,
},
.probe = mtk8250_probe,
- .remove_new = mtk8250_remove,
+ .remove = mtk8250_remove,
};
module_platform_driver(mtk8250_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c
new file mode 100644
index 000000000000..b10a42d2ad63
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_ni.c
@@ -0,0 +1,461 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * NI 16550 UART Driver
+ *
+ * The National Instruments (NI) 16550 is a UART that is compatible with the
+ * TL16C550C and OX16C950B register interfaces, but has additional functions
+ * for RS-485 transceiver control. This driver implements support for the
+ * additional functionality on top of the standard serial8250 core.
+ *
+ * Copyright 2012-2023 National Instruments Corporation
+ */
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/clk.h>
+
+#include "8250.h"
+
+/* Extra bits in UART_ACR */
+#define NI16550_ACR_AUTO_DTR_EN BIT(4)
+
+/* TFS - TX FIFO Size */
+#define NI16550_TFS_OFFSET 0x0C
+/* RFS - RX FIFO Size */
+#define NI16550_RFS_OFFSET 0x0D
+
+/* PMR - Port Mode Register */
+#define NI16550_PMR_OFFSET 0x0E
+/* PMR[1:0] - Port Capabilities */
+#define NI16550_PMR_CAP_MASK GENMASK(1, 0)
+#define NI16550_PMR_NOT_IMPL FIELD_PREP(NI16550_PMR_CAP_MASK, 0) /* not implemented */
+#define NI16550_PMR_CAP_RS232 FIELD_PREP(NI16550_PMR_CAP_MASK, 1) /* RS-232 capable */
+#define NI16550_PMR_CAP_RS485 FIELD_PREP(NI16550_PMR_CAP_MASK, 2) /* RS-485 capable */
+#define NI16550_PMR_CAP_DUAL FIELD_PREP(NI16550_PMR_CAP_MASK, 3) /* dual-port */
+/* PMR[4] - Interface Mode */
+#define NI16550_PMR_MODE_MASK GENMASK(4, 4)
+#define NI16550_PMR_MODE_RS232 FIELD_PREP(NI16550_PMR_MODE_MASK, 0) /* currently 232 */
+#define NI16550_PMR_MODE_RS485 FIELD_PREP(NI16550_PMR_MODE_MASK, 1) /* currently 485 */
+
+/* PCR - Port Control Register */
+/*
+ * Wire Mode | Tx enabled? | Rx enabled?
+ * ---------------|----------------------|--------------------------
+ * PCR_RS422 | Always | Always
+ * PCR_ECHO_RS485 | When DTR asserted | Always
+ * PCR_DTR_RS485 | When DTR asserted | Disabled when TX enabled
+ * PCR_AUTO_RS485 | When data in TX FIFO | Disabled when TX enabled
+ */
+#define NI16550_PCR_OFFSET 0x0F
+#define NI16550_PCR_WIRE_MODE_MASK GENMASK(1, 0)
+#define NI16550_PCR_RS422 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 0)
+#define NI16550_PCR_ECHO_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 1)
+#define NI16550_PCR_DTR_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 2)
+#define NI16550_PCR_AUTO_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 3)
+#define NI16550_PCR_TXVR_ENABLE_BIT BIT(3)
+#define NI16550_PCR_RS485_TERMINATION_BIT BIT(6)
+
+/* flags for ni16550_device_info */
+#define NI_HAS_PMR BIT(0)
+
+struct ni16550_device_info {
+ u32 uartclk;
+ u8 prescaler;
+ u8 flags;
+};
+
+struct ni16550_data {
+ int line;
+ struct clk *clk;
+};
+
+static int ni16550_enable_transceivers(struct uart_port *port)
+{
+ u8 pcr;
+
+ pcr = port->serial_in(port, NI16550_PCR_OFFSET);
+ pcr |= NI16550_PCR_TXVR_ENABLE_BIT;
+ dev_dbg(port->dev, "enable transceivers: write pcr: 0x%02x\n", pcr);
+ port->serial_out(port, NI16550_PCR_OFFSET, pcr);
+
+ return 0;
+}
+
+static int ni16550_disable_transceivers(struct uart_port *port)
+{
+ u8 pcr;
+
+ pcr = port->serial_in(port, NI16550_PCR_OFFSET);
+ pcr &= ~NI16550_PCR_TXVR_ENABLE_BIT;
+ dev_dbg(port->dev, "disable transceivers: write pcr: 0x%02x\n", pcr);
+ port->serial_out(port, NI16550_PCR_OFFSET, pcr);
+
+ return 0;
+}
+
+static int ni16550_rs485_config(struct uart_port *port,
+ struct ktermios *termios,
+ struct serial_rs485 *rs485)
+{
+ struct uart_8250_port *up = container_of(port, struct uart_8250_port, port);
+ u8 pcr;
+
+ pcr = serial_in(up, NI16550_PCR_OFFSET);
+ pcr &= ~NI16550_PCR_WIRE_MODE_MASK;
+
+ if ((rs485->flags & SER_RS485_MODE_RS422) ||
+ !(rs485->flags & SER_RS485_ENABLED)) {
+ /* RS-422 */
+ pcr |= NI16550_PCR_RS422;
+ up->acr &= ~NI16550_ACR_AUTO_DTR_EN;
+ } else {
+ /* RS-485 2-wire Auto */
+ pcr |= NI16550_PCR_AUTO_RS485;
+ up->acr |= NI16550_ACR_AUTO_DTR_EN;
+ }
+
+ dev_dbg(port->dev, "config rs485: write pcr: 0x%02x, acr: %02x\n", pcr, up->acr);
+ serial_out(up, NI16550_PCR_OFFSET, pcr);
+ serial_icr_write(up, UART_ACR, up->acr);
+
+ return 0;
+}
+
+static bool is_pmr_rs232_mode(struct uart_8250_port *up)
+{
+ u8 pmr = serial_in(up, NI16550_PMR_OFFSET);
+ u8 pmr_mode = pmr & NI16550_PMR_MODE_MASK;
+ u8 pmr_cap = pmr & NI16550_PMR_CAP_MASK;
+
+ /*
+ * If the PMR is not implemented, then by default NI UARTs are
+ * connected to RS-485 transceivers
+ */
+ if (pmr_cap == NI16550_PMR_NOT_IMPL)
+ return false;
+
+ if (pmr_cap == NI16550_PMR_CAP_DUAL)
+ /*
+ * If the port is dual-mode capable, then read the mode bit
+ * to know the current mode
+ */
+ return pmr_mode == NI16550_PMR_MODE_RS232;
+ /*
+ * If it is not dual-mode capable, then decide based on the
+ * capability
+ */
+ return pmr_cap == NI16550_PMR_CAP_RS232;
+}
+
+static void ni16550_config_prescaler(struct uart_8250_port *up,
+ u8 prescaler)
+{
+ /*
+ * Page in the Enhanced Mode Registers
+ * Sets EFR[4] for Enhanced Mode.
+ */
+ u8 lcr_value;
+ u8 efr_value;
+
+ lcr_value = serial_in(up, UART_LCR);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+
+ efr_value = serial_in(up, UART_EFR);
+ efr_value |= UART_EFR_ECB;
+
+ serial_out(up, UART_EFR, efr_value);
+
+ /* Page out the Enhanced Mode Registers */
+ serial_out(up, UART_LCR, lcr_value);
+
+ /* Set prescaler to CPR register. */
+ serial_out(up, UART_SCR, UART_CPR);
+ serial_out(up, UART_ICR, prescaler);
+}
+
+static const struct serial_rs485 ni16550_rs485_supported = {
+ .flags = SER_RS485_ENABLED | SER_RS485_MODE_RS422 | SER_RS485_RTS_ON_SEND |
+ SER_RS485_RTS_AFTER_SEND,
+ /*
+ * delay_rts_* and RX_DURING_TX are not supported.
+ *
+ * RTS_{ON,AFTER}_SEND are supported, but ignored; the transceiver
+ * is connected in only one way and we don't need userspace to tell
+ * us, but want to retain compatibility with applications that do.
+ */
+};
+
+static void ni16550_rs485_setup(struct uart_port *port)
+{
+ port->rs485_config = ni16550_rs485_config;
+ port->rs485_supported = ni16550_rs485_supported;
+ /*
+ * The hardware comes up by default in 2-wire auto mode and we
+ * set the flags to represent that
+ */
+ port->rs485.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
+}
+
+static int ni16550_port_startup(struct uart_port *port)
+{
+ int ret;
+
+ ret = serial8250_do_startup(port);
+ if (ret)
+ return ret;
+
+ return ni16550_enable_transceivers(port);
+}
+
+static void ni16550_port_shutdown(struct uart_port *port)
+{
+ ni16550_disable_transceivers(port);
+
+ serial8250_do_shutdown(port);
+}
+
+static int ni16550_get_regs(struct platform_device *pdev,
+ struct uart_port *port)
+{
+ struct resource *regs;
+
+ regs = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (regs) {
+ port->iotype = UPIO_PORT;
+ port->iobase = regs->start;
+
+ return 0;
+ }
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (regs) {
+ port->iotype = UPIO_MEM;
+ port->mapbase = regs->start;
+ port->mapsize = resource_size(regs);
+ port->flags |= UPF_IOREMAP;
+
+ port->membase = devm_ioremap(&pdev->dev, port->mapbase,
+ port->mapsize);
+ if (!port->membase)
+ return -ENOMEM;
+
+ return 0;
+ }
+
+ dev_err(&pdev->dev, "no registers defined\n");
+ return -EINVAL;
+}
+
+/*
+ * Very old implementations don't have the TFS or RFS registers
+ * defined, so we may read all-0s or all-1s. For such devices,
+ * assume a FIFO size of 128.
+ */
+static u8 ni16550_read_fifo_size(struct uart_8250_port *uart, int reg)
+{
+ u8 value = serial_in(uart, reg);
+
+ if (value == 0x00 || value == 0xFF)
+ return 128;
+
+ return value;
+}
+
+static void ni16550_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ up->mcr |= UART_MCR_CLKSEL;
+ serial8250_do_set_mctrl(port, mctrl);
+}
+
+static int ni16550_probe(struct platform_device *pdev)
+{
+ const struct ni16550_device_info *info;
+ struct device *dev = &pdev->dev;
+ struct uart_8250_port uart = {};
+ unsigned int txfifosz, rxfifosz;
+ unsigned int prescaler = 0;
+ struct ni16550_data *data;
+ const char *portmode;
+ bool rs232_property;
+ int ret;
+ int irq;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&uart.port.lock);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = ni16550_get_regs(pdev, &uart.port);
+ if (ret < 0)
+ return ret;
+
+ /* early setup so that serial_in()/serial_out() work */
+ serial8250_set_defaults(&uart);
+
+ info = device_get_match_data(dev);
+
+ uart.port.dev = dev;
+ uart.port.irq = irq;
+ uart.port.irqflags = IRQF_SHARED;
+ uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF
+ | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+ uart.port.startup = ni16550_port_startup;
+ uart.port.shutdown = ni16550_port_shutdown;
+
+ /*
+ * Hardware instantiation of FIFO sizes are held in registers.
+ */
+ txfifosz = ni16550_read_fifo_size(&uart, NI16550_TFS_OFFSET);
+ rxfifosz = ni16550_read_fifo_size(&uart, NI16550_RFS_OFFSET);
+
+ dev_dbg(dev, "NI 16550 has TX FIFO size %u, RX FIFO size %u\n",
+ txfifosz, rxfifosz);
+
+ uart.port.type = PORT_16550A;
+ uart.port.fifosize = txfifosz;
+ uart.tx_loadsz = txfifosz;
+ uart.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
+ uart.capabilities = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR;
+
+ /*
+ * Declaration of the base clock frequency can come from one of:
+ * - static declaration in this driver (for older ACPI IDs)
+ * - a "clock-frquency" ACPI
+ */
+ if (info->uartclk)
+ uart.port.uartclk = info->uartclk;
+ if (device_property_read_u32(dev, "clock-frequency",
+ &uart.port.uartclk)) {
+ data->clk = devm_clk_get_enabled(dev, NULL);
+ if (!IS_ERR(data->clk))
+ uart.port.uartclk = clk_get_rate(data->clk);
+ }
+
+ if (!uart.port.uartclk) {
+ dev_err(dev, "unable to determine clock frequency!\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ if (info->prescaler)
+ prescaler = info->prescaler;
+ device_property_read_u32(dev, "clock-prescaler", &prescaler);
+
+ if (prescaler != 0) {
+ uart.port.set_mctrl = ni16550_set_mctrl;
+ ni16550_config_prescaler(&uart, (u8)prescaler);
+ }
+
+ /*
+ * The determination of whether or not this is an RS-485 or RS-232 port
+ * can come from the PMR (if present), otherwise we're solely an RS-485
+ * port.
+ *
+ * This is a device-specific property, and there are old devices in the
+ * field using "transceiver" as an ACPI property, so we have to check
+ * for that as well.
+ */
+ if (!device_property_read_string(dev, "transceiver", &portmode)) {
+ rs232_property = strncmp(portmode, "RS-232", 6) == 0;
+
+ dev_dbg(dev, "port is in %s mode (via device property)\n",
+ rs232_property ? "RS-232" : "RS-485");
+ } else if (info->flags & NI_HAS_PMR) {
+ rs232_property = is_pmr_rs232_mode(&uart);
+
+ dev_dbg(dev, "port is in %s mode (via PMR)\n",
+ rs232_property ? "RS-232" : "RS-485");
+ } else {
+ rs232_property = 0;
+
+ dev_dbg(dev, "port is fixed as RS-485\n");
+ }
+
+ if (!rs232_property) {
+ /*
+ * Neither the 'transceiver' property nor the PMR indicate
+ * that this is an RS-232 port, so it must be an RS-485 one.
+ */
+ ni16550_rs485_setup(&uart.port);
+ }
+
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0)
+ goto err;
+ data->line = ret;
+
+ platform_set_drvdata(pdev, data);
+ return 0;
+
+err:
+ return ret;
+}
+
+static void ni16550_remove(struct platform_device *pdev)
+{
+ struct ni16550_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+}
+
+#ifdef CONFIG_ACPI
+/* NI 16550 RS-485 Interface */
+static const struct ni16550_device_info nic7750 = {
+ .uartclk = 33333333,
+};
+
+/* NI CVS-145x RS-485 Interface */
+static const struct ni16550_device_info nic7772 = {
+ .uartclk = 1843200,
+ .flags = NI_HAS_PMR,
+};
+
+/* NI cRIO-904x RS-485 Interface */
+static const struct ni16550_device_info nic792b = {
+ /* Sets UART clock rate to 22.222 MHz with 1.125 prescale */
+ .uartclk = 22222222,
+ .prescaler = 0x09,
+};
+
+/* NI sbRIO 96x8 RS-232/485 Interfaces */
+static const struct ni16550_device_info nic7a69 = {
+ /* Set UART clock rate to 29.629 MHz with 1.125 prescale */
+ .uartclk = 29629629,
+ .prescaler = 0x09,
+};
+static const struct acpi_device_id ni16550_acpi_match[] = {
+ { "NIC7750", (kernel_ulong_t)&nic7750 },
+ { "NIC7772", (kernel_ulong_t)&nic7772 },
+ { "NIC792B", (kernel_ulong_t)&nic792b },
+ { "NIC7A69", (kernel_ulong_t)&nic7a69 },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, ni16550_acpi_match);
+#endif
+
+static struct platform_driver ni16550_driver = {
+ .driver = {
+ .name = "ni16550",
+ .acpi_match_table = ACPI_PTR(ni16550_acpi_match),
+ },
+ .probe = ni16550_probe,
+ .remove = ni16550_remove,
+};
+
+module_platform_driver(ni16550_driver);
+
+MODULE_AUTHOR("Emerson Electric Co.");
+MODULE_DESCRIPTION("NI 16550 Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c
index 5d1dd992d8fb..11c860ea80f6 100644
--- a/drivers/tty/serial/8250/8250_of.c
+++ b/drivers/tty/serial/8250/8250_of.c
@@ -18,6 +18,7 @@
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/reset.h>
+#include <linux/notifier.h>
#include "8250.h"
@@ -26,6 +27,7 @@ struct of_serial_info {
struct reset_control *rst;
int type;
int line;
+ struct notifier_block clk_notifier;
};
/* Nuvoton NPCM timeout register */
@@ -58,6 +60,26 @@ static int npcm_setup(struct uart_port *port)
return 0;
}
+static inline struct of_serial_info *clk_nb_to_info(struct notifier_block *nb)
+{
+ return container_of(nb, struct of_serial_info, clk_notifier);
+}
+
+static int of_platform_serial_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ struct of_serial_info *info = clk_nb_to_info(nb);
+ struct uart_8250_port *port8250 = serial8250_get_port(info->line);
+ struct clk_notifier_data *ndata = data;
+
+ if (event == POST_RATE_CHANGE) {
+ serial8250_update_uartclk(&port8250->port, ndata->new_rate);
+ return NOTIFY_OK;
+ }
+
+ return NOTIFY_DONE;
+}
+
/*
* Fill a struct uart_port for a given device node
*/
@@ -88,7 +110,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
spin_lock_init(&port->lock);
if (resource_type(&resource) == IORESOURCE_IO) {
- port->iotype = UPIO_PORT;
port->iobase = resource.start;
} else {
port->mapbase = resource.start;
@@ -218,7 +239,19 @@ static int of_platform_serial_probe(struct platform_device *ofdev)
info->type = port_type;
info->line = ret;
platform_set_drvdata(ofdev, info);
+
+ if (info->clk) {
+ info->clk_notifier.notifier_call = of_platform_serial_clk_notifier_cb;
+ ret = clk_notifier_register(info->clk, &info->clk_notifier);
+ if (ret) {
+ dev_err_probe(port8250.port.dev, ret, "Failed to set the clock notifier\n");
+ goto err_unregister;
+ }
+ }
+
return 0;
+err_unregister:
+ serial8250_unregister_port(info->line);
err_dispose:
pm_runtime_put_sync(&ofdev->dev);
pm_runtime_disable(&ofdev->dev);
@@ -234,6 +267,9 @@ static void of_platform_serial_remove(struct platform_device *ofdev)
{
struct of_serial_info *info = platform_get_drvdata(ofdev);
+ if (info->clk)
+ clk_notifier_unregister(info->clk, &info->clk_notifier);
+
serial8250_unregister_port(info->line);
reset_control_assert(info->rst);
@@ -315,7 +351,7 @@ static struct platform_driver of_platform_serial_driver = {
.pm = &of_serial_pm_ops,
},
.probe = of_platform_serial_probe,
- .remove_new = of_platform_serial_remove,
+ .remove = of_platform_serial_remove,
};
module_platform_driver(of_platform_serial_driver);
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 66901d93089a..2a0ce11f405d 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -19,7 +19,6 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
@@ -28,7 +27,6 @@
#include <linux/pm_wakeirq.h>
#include <linux/dma-mapping.h>
#include <linux/sys_soc.h>
-#include <linux/pm_domain.h>
#include "8250.h"
@@ -116,11 +114,9 @@
/* RX FIFO occupancy indicator */
#define UART_OMAP_RX_LVL 0x19
-/*
- * Copy of the genpd flags for the console.
- * Only used if console suspend is disabled
- */
-static unsigned int genpd_flags_console;
+/* Timeout low and High */
+#define UART_OMAP_TO_L 0x26
+#define UART_OMAP_TO_H 0x27
struct omap8250_priv {
void __iomem *membase;
@@ -141,7 +137,6 @@ struct omap8250_priv {
atomic_t active;
bool is_suspending;
int wakeirq;
- int wakeups_enabled;
u32 latency;
u32 calc_latency;
struct pm_qos_request pm_qos_request;
@@ -370,7 +365,7 @@ static void omap8250_restore_regs(struct uart_8250_port *up)
if (up->port.rs485.flags & SER_RS485_ENABLED &&
up->port.rs485_config == serial8250_em485_config)
- serial8250_em485_stop_tx(up);
+ serial8250_em485_stop_tx(up, true);
}
/*
@@ -417,7 +412,13 @@ static void omap_8250_set_termios(struct uart_port *port,
*/
uart_update_timeout(port, termios->c_cflag, baud);
- up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ /*
+ * Specify which conditions may be considered for error
+ * handling and the ignoring of characters. The actual
+ * ignoring of characters only occurs if the bit is set
+ * in @ignore_status_mask as well.
+ */
+ up->port.read_status_mask = UART_LSR_OE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (termios->c_iflag & (IGNBRK | PARMRK))
@@ -664,13 +665,25 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
/*
* On K3 SoCs, it is observed that RX TIMEOUT is signalled after
- * FIFO has been drained, in which case a dummy read of RX FIFO
- * is required to clear RX TIMEOUT condition.
+ * FIFO has been drained or erroneously.
+ * So apply solution of Errata i2310 as mentioned in
+ * https://www.ti.com/lit/pdf/sprz536
*/
if (priv->habit & UART_RX_TIMEOUT_QUIRK &&
(iir & UART_IIR_RX_TIMEOUT) == UART_IIR_RX_TIMEOUT &&
serial_port_in(port, UART_OMAP_RX_LVL) == 0) {
- serial_port_in(port, UART_RX);
+ unsigned char efr2, timeout_h, timeout_l;
+
+ efr2 = serial_in(up, UART_OMAP_EFR2);
+ timeout_h = serial_in(up, UART_OMAP_TO_H);
+ timeout_l = serial_in(up, UART_OMAP_TO_L);
+ serial_out(up, UART_OMAP_TO_H, 0xFF);
+ serial_out(up, UART_OMAP_TO_L, 0xFF);
+ serial_out(up, UART_OMAP_EFR2, UART_OMAP_EFR2_TIMEOUT_BEHAVE);
+ serial_in(up, UART_IIR);
+ serial_out(up, UART_OMAP_EFR2, efr2);
+ serial_out(up, UART_OMAP_TO_H, timeout_h);
+ serial_out(up, UART_OMAP_TO_L, timeout_l);
}
/* Stop processing interrupts on input overrun */
@@ -679,7 +692,7 @@ static irqreturn_t omap8250_irq(int irq, void *dev_id)
/* Synchronize UART_IER access against the console. */
uart_port_lock(port);
- up->ier = port->serial_in(port, UART_IER);
+ up->ier = serial_port_in(port, UART_IER);
if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) {
port->ops->stop_rx(port);
} else {
@@ -769,12 +782,12 @@ static void omap_8250_shutdown(struct uart_port *port)
struct uart_8250_port *up = up_to_u8250p(port);
struct omap8250_priv *priv = port->private_data;
+ pm_runtime_get_sync(port->dev);
+
flush_work(&priv->qos_work);
if (up->dma)
omap_8250_rx_dma_flush(up);
- pm_runtime_get_sync(port->dev);
-
serial_out(up, UART_OMAP_WER, 0);
if (priv->habit & UART_HAS_EFR2)
serial_out(up, UART_OMAP_EFR2, 0x0);
@@ -831,7 +844,6 @@ static void omap_8250_unthrottle(struct uart_port *port)
if (up->dma)
up->dma->rx_dma(up);
up->ier |= UART_IER_RLSI | UART_IER_RDI;
- port->read_status_mask |= UART_LSR_DR;
serial_out(up, UART_IER, up->ier);
uart_port_unlock_irqrestore(port, flags);
@@ -1094,7 +1106,7 @@ static void omap_8250_dma_tx_complete(void *param)
{
struct uart_8250_port *p = param;
struct uart_8250_dma *dma = p->dma;
- struct circ_buf *xmit = &p->port.state->xmit;
+ struct tty_port *tport = &p->port.state->port;
unsigned long flags;
bool en_thri = false;
struct omap8250_priv *priv = p->port.private_data;
@@ -1113,10 +1125,10 @@ static void omap_8250_dma_tx_complete(void *param)
omap8250_restore_regs(p);
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&p->port);
- if (!uart_circ_empty(xmit) && !uart_tx_stopped(&p->port)) {
+ if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(&p->port)) {
int ret;
ret = omap_8250_tx_dma(p);
@@ -1138,14 +1150,15 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
{
struct uart_8250_dma *dma = p->dma;
struct omap8250_priv *priv = p->port.private_data;
- struct circ_buf *xmit = &p->port.state->xmit;
+ struct tty_port *tport = &p->port.state->port;
struct dma_async_tx_descriptor *desc;
- unsigned int skip_byte = 0;
+ struct scatterlist sg;
+ int skip_byte = -1;
int ret;
if (dma->tx_running)
return 0;
- if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
+ if (uart_tx_stopped(&p->port) || kfifo_is_empty(&tport->xmit_fifo)) {
/*
* Even if no data, we need to return an error for the two cases
@@ -1160,8 +1173,18 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
return 0;
}
- dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ sg_init_table(&sg, 1);
+ ret = kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
+ UART_XMIT_SIZE, dma->tx_addr);
+ if (ret != 1) {
+ serial8250_clear_THRI(p);
+ return 0;
+ }
+
+ dma->tx_size = sg_dma_len(&sg);
+
if (priv->habit & OMAP_DMA_TX_KICK) {
+ unsigned char c;
u8 tx_lvl;
/*
@@ -1188,12 +1211,17 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
ret = -EINVAL;
goto err;
}
- skip_byte = 1;
+ if (!kfifo_get(&tport->xmit_fifo, &c)) {
+ ret = -EINVAL;
+ goto err;
+ }
+ skip_byte = c;
+ /* now we need to recompute due to kfifo_get */
+ kfifo_dma_out_prepare_mapped(&tport->xmit_fifo, &sg, 1,
+ UART_XMIT_SIZE, dma->tx_addr);
}
- desc = dmaengine_prep_slave_single(dma->txchan,
- dma->tx_addr + xmit->tail + skip_byte,
- dma->tx_size - skip_byte, DMA_MEM_TO_DEV,
+ desc = dmaengine_prep_slave_sg(dma->txchan, &sg, 1, DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
ret = -EBUSY;
@@ -1215,11 +1243,13 @@ static int omap_8250_tx_dma(struct uart_8250_port *p)
dma->tx_err = 0;
serial8250_clear_THRI(p);
- if (skip_byte)
- serial_out(p, UART_TX, xmit->buf[xmit->tail]);
- return 0;
+ ret = 0;
+ goto out_skip;
err:
dma->tx_err = 1;
+out_skip:
+ if (skip_byte >= 0)
+ serial_out(p, UART_TX, skip_byte);
return ret;
}
@@ -1279,7 +1309,7 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir,
/*
* This is mostly serial8250_handle_irq(). We have a slightly different DMA
- * hoook for RX/TX and need different logic for them in the ISR. Therefore we
+ * hook for RX/TX and need different logic for them in the ISR. Therefore we
* use the default routine in the non-DMA case and this one for with DMA.
*/
static int omap_8250_dma_handle_irq(struct uart_port *port)
@@ -1308,12 +1338,12 @@ static int omap_8250_dma_handle_irq(struct uart_port *port)
serial8250_modem_status(up);
if (status & UART_LSR_THRE && up->dma->tx_err) {
if (uart_tx_stopped(&up->port) ||
- uart_circ_empty(&up->port.state->xmit)) {
+ kfifo_is_empty(&up->port.state->port.xmit_fifo)) {
up->dma->tx_err = 0;
serial8250_tx_chars(up);
} else {
/*
- * try again due to an earlier failer which
+ * try again due to an earlier failure which
* might have been resolved by now.
*/
if (omap_8250_tx_dma(up))
@@ -1497,7 +1527,10 @@ static int omap8250_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
- device_init_wakeup(&pdev->dev, true);
+ device_set_wakeup_capable(&pdev->dev, true);
+ if (of_property_read_bool(np, "wakeup-source"))
+ device_set_wakeup_enable(&pdev->dev, true);
+
pm_runtime_enable(&pdev->dev);
pm_runtime_use_autosuspend(&pdev->dev);
@@ -1555,7 +1588,7 @@ static int omap8250_probe(struct platform_device *pdev)
ret = devm_request_irq(&pdev->dev, up.port.irq, omap8250_irq, 0,
dev_name(&pdev->dev), priv);
if (ret < 0)
- return ret;
+ goto err;
priv->wakeirq = irq_of_parse_and_map(np, 1);
@@ -1596,7 +1629,7 @@ static void omap8250_remove(struct platform_device *pdev)
flush_work(&priv->qos_work);
pm_runtime_disable(&pdev->dev);
cpu_latency_qos_remove_request(&priv->pm_qos_request);
- device_init_wakeup(&pdev->dev, false);
+ device_set_wakeup_capable(&pdev->dev, false);
}
static int omap8250_prepare(struct device *dev)
@@ -1622,7 +1655,6 @@ static int omap8250_suspend(struct device *dev)
{
struct omap8250_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
- struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain);
int err = 0;
serial8250_suspend_port(priv->line);
@@ -1633,19 +1665,8 @@ static int omap8250_suspend(struct device *dev)
if (!device_may_wakeup(dev))
priv->wer = 0;
serial_out(up, UART_OMAP_WER, priv->wer);
- if (uart_console(&up->port)) {
- if (console_suspend_enabled)
- err = pm_runtime_force_suspend(dev);
- else {
- /*
- * The pd shall not be powered-off (no console suspend).
- * Make copy of genpd flags before to set it always on.
- * The original value is restored during the resume.
- */
- genpd_flags_console = genpd->flags;
- genpd->flags |= GENPD_FLAG_ALWAYS_ON;
- }
- }
+ if (uart_console(&up->port) && console_suspend_enabled)
+ err = pm_runtime_force_suspend(dev);
flush_work(&priv->qos_work);
return err;
@@ -1655,16 +1676,12 @@ static int omap8250_resume(struct device *dev)
{
struct omap8250_priv *priv = dev_get_drvdata(dev);
struct uart_8250_port *up = serial8250_get_port(priv->line);
- struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain);
int err;
if (uart_console(&up->port) && console_suspend_enabled) {
- if (console_suspend_enabled) {
- err = pm_runtime_force_resume(dev);
- if (err)
- return err;
- } else
- genpd->flags = genpd_flags_console;
+ err = pm_runtime_force_resume(dev);
+ if (err)
+ return err;
}
serial8250_resume_port(priv->line);
@@ -1855,7 +1872,7 @@ static struct platform_driver omap8250_platform_driver = {
.of_match_table = omap8250_dt_ids,
},
.probe = omap8250_probe,
- .remove_new = omap8250_remove,
+ .remove = omap8250_remove,
};
module_platform_driver(omap8250_platform_driver);
diff --git a/drivers/tty/serial/8250/8250_parisc.c b/drivers/tty/serial/8250/8250_parisc.c
index 948d0a1c6ae8..4ba05a98791c 100644
--- a/drivers/tty/serial/8250/8250_parisc.c
+++ b/drivers/tty/serial/8250/8250_parisc.c
@@ -127,4 +127,5 @@ static int __init probe_serial_gsc(void)
module_init(probe_serial_gsc);
+MODULE_DESCRIPTION("Serial Device Initialisation for Lasi/Asp/Wax/Dino");
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index e2e4f99f9d34..73c200127b08 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -64,23 +64,17 @@
#define PCIE_DEVICE_ID_NEO_2_OX_IBM 0x00F6
#define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
#define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
-#define PCI_VENDOR_ID_WCH 0x4348
-#define PCI_DEVICE_ID_WCH_CH352_2S 0x3253
-#define PCI_DEVICE_ID_WCH_CH353_4S 0x3453
-#define PCI_DEVICE_ID_WCH_CH353_2S1PF 0x5046
-#define PCI_DEVICE_ID_WCH_CH353_1S1P 0x5053
-#define PCI_DEVICE_ID_WCH_CH353_2S1P 0x7053
-#define PCI_DEVICE_ID_WCH_CH355_4S 0x7173
+
+#define PCI_DEVICE_ID_WCHCN_CH352_2S 0x3253
+#define PCI_DEVICE_ID_WCHCN_CH355_4S 0x7173
+
#define PCI_VENDOR_ID_AGESTAR 0x5372
#define PCI_DEVICE_ID_AGESTAR_9375 0x6872
#define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a
#define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e
-#define PCIE_VENDOR_ID_WCH 0x1c00
-#define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250
-#define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470
-#define PCIE_DEVICE_ID_WCH_CH384_8S 0x3853
-#define PCIE_DEVICE_ID_WCH_CH382_2S 0x3253
+#define PCI_DEVICE_ID_WCHIC_CH384_4S 0x3470
+#define PCI_DEVICE_ID_WCHIC_CH384_8S 0x3853
#define PCI_DEVICE_ID_MOXA_CP102E 0x1024
#define PCI_DEVICE_ID_MOXA_CP102EL 0x1025
@@ -964,6 +958,9 @@ static int pci_ite887x_init(struct pci_dev *dev)
struct resource *iobase = NULL;
u32 miscr, uartbar, ioport;
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT))
+ return serial_8250_warn_need_ioport(dev);
+
/* search for the base-ioport */
for (i = 0; i < ARRAY_SIZE(inta_addr); i++) {
iobase = request_region(inta_addr[i], ITE_887x_IOSIZE,
@@ -1277,7 +1274,7 @@ static void pci_oxsemi_tornado_set_divisor(struct uart_port *port,
serial_icr_write(up, UART_TCR, tcr);
serial_icr_write(up, UART_CPR, cpr);
serial_icr_write(up, UART_CKS, cpr2);
- serial8250_do_set_divisor(port, baud, quot, 0);
+ serial8250_do_set_divisor(port, baud, quot);
}
/*
@@ -1514,6 +1511,9 @@ static int pci_quatech_init(struct pci_dev *dev)
const struct pci_device_id *match;
bool amcc = false;
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT))
+ return serial_8250_warn_need_ioport(dev);
+
match = pci_match_id(quatech_cards, dev);
if (match)
amcc = match->driver_data;
@@ -1538,6 +1538,9 @@ static int pci_quatech_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
{
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT))
+ return serial_8250_warn_need_ioport(priv->dev);
+
/* Needed by pci_quatech calls below */
port->port.iobase = pci_resource_start(priv->dev, FL_GET_BASE(board->flags));
/* Set up the clocking */
@@ -1655,6 +1658,9 @@ static int pci_fintek_setup(struct serial_private *priv,
u8 config_base;
u16 iobase;
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT))
+ return serial_8250_warn_need_ioport(pdev);
+
config_base = 0x40 + 0x08 * idx;
/* Get the io address from configuration space */
@@ -1686,6 +1692,9 @@ static int pci_fintek_init(struct pci_dev *dev)
u8 config_base;
struct serial_private *priv = pci_get_drvdata(dev);
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT))
+ return serial_8250_warn_need_ioport(dev);
+
if (!(pci_resource_flags(dev, 5) & IORESOURCE_IO) ||
!(pci_resource_flags(dev, 4) & IORESOURCE_IO) ||
!(pci_resource_flags(dev, 3) & IORESOURCE_IO))
@@ -1864,6 +1873,9 @@ static int kt_serial_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
{
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT))
+ return serial_8250_warn_need_ioport(priv->dev);
+
port->port.flags |= UPF_BUG_THRE;
port->port.serial_in = kt_serial_in;
port->port.handle_break = kt_handle_break;
@@ -1884,6 +1896,9 @@ pci_wch_ch353_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
{
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT))
+ return serial_8250_warn_need_ioport(priv->dev);
+
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16550A;
return pci_default_setup(priv, board, port, idx);
@@ -1894,6 +1909,9 @@ pci_wch_ch355_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
{
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT))
+ return serial_8250_warn_need_ioport(priv->dev);
+
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16550A;
return pci_default_setup(priv, board, port, idx);
@@ -1904,6 +1922,9 @@ pci_wch_ch38x_setup(struct serial_private *priv,
const struct pciserial_board *board,
struct uart_8250_port *port, int idx)
{
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT))
+ return serial_8250_warn_need_ioport(priv->dev);
+
port->port.flags |= UPF_FIXED_TYPE;
port->port.type = PORT_16850;
return pci_default_setup(priv, board, port, idx);
@@ -1918,6 +1939,8 @@ static int pci_wch_ch38x_init(struct pci_dev *dev)
int max_port;
unsigned long iobase;
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT))
+ return serial_8250_warn_need_ioport(dev);
switch (dev->device) {
case 0x3853: /* 8 ports */
@@ -1937,6 +1960,11 @@ static void pci_wch_ch38x_exit(struct pci_dev *dev)
{
unsigned long iobase;
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT)) {
+ serial_8250_warn_need_ioport(dev);
+ return;
+ }
+
iobase = pci_resource_start(dev, 0);
outb(0x0, iobase + CH384_XINT_ENABLE_REG);
}
@@ -1985,6 +2013,17 @@ enum {
MOXA_SUPP_RS485 = BIT(2),
};
+static unsigned short moxa_get_nports(unsigned short device)
+{
+ switch (device) {
+ case PCI_DEVICE_ID_MOXA_CP116E_A_A:
+ case PCI_DEVICE_ID_MOXA_CP116E_A_B:
+ return 8;
+ }
+
+ return FIELD_GET(0x00F0, device);
+}
+
static bool pci_moxa_is_mini_pcie(unsigned short device)
{
if (device == PCI_DEVICE_ID_MOXA_CP102N ||
@@ -2038,9 +2077,12 @@ static int pci_moxa_init(struct pci_dev *dev)
{
unsigned short device = dev->device;
resource_size_t iobar_addr = pci_resource_start(dev, 2);
- unsigned int num_ports = (device & 0x00F0) >> 4, i;
+ unsigned int i, num_ports = moxa_get_nports(device);
u8 val, init_mode = MOXA_RS232;
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT))
+ return serial_8250_warn_need_ioport(dev);
+
if (!(pci_moxa_supported_rs(dev) & MOXA_SUPP_RS232)) {
init_mode = MOXA_RS422;
}
@@ -2073,6 +2115,9 @@ pci_moxa_setup(struct serial_private *priv,
unsigned int bar = FL_GET_BASE(board->flags);
int offset;
+ if (!IS_ENABLED(CONFIG_HAS_IOPORT))
+ return serial_8250_warn_need_ioport(priv->dev);
+
if (board->num_ports == 4 && idx == 3)
offset = 7 * board->uart_offset;
else
@@ -2683,6 +2728,22 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.setup = pci_oxsemi_tornado_setup,
},
{
+ .vendor = PCI_VENDOR_ID_INTASHIELD,
+ .device = 0x4026,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_oxsemi_tornado_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_INTASHIELD,
+ .device = 0x4021,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_oxsemi_tornado_setup,
+ },
+ {
.vendor = PCI_VENDOR_ID_INTEL,
.device = 0x8811,
.subvendor = PCI_ANY_ID,
@@ -2766,80 +2827,80 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
},
/* WCH CH353 1S1P card (16550 clone) */
{
- .vendor = PCI_VENDOR_ID_WCH,
- .device = PCI_DEVICE_ID_WCH_CH353_1S1P,
+ .vendor = PCI_VENDOR_ID_WCHCN,
+ .device = PCI_DEVICE_ID_WCHCN_CH353_1S1P,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup,
},
/* WCH CH353 2S1P card (16550 clone) */
{
- .vendor = PCI_VENDOR_ID_WCH,
- .device = PCI_DEVICE_ID_WCH_CH353_2S1P,
+ .vendor = PCI_VENDOR_ID_WCHCN,
+ .device = PCI_DEVICE_ID_WCHCN_CH353_2S1P,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup,
},
/* WCH CH353 4S card (16550 clone) */
{
- .vendor = PCI_VENDOR_ID_WCH,
- .device = PCI_DEVICE_ID_WCH_CH353_4S,
+ .vendor = PCI_VENDOR_ID_WCHCN,
+ .device = PCI_DEVICE_ID_WCHCN_CH353_4S,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup,
},
/* WCH CH353 2S1PF card (16550 clone) */
{
- .vendor = PCI_VENDOR_ID_WCH,
- .device = PCI_DEVICE_ID_WCH_CH353_2S1PF,
+ .vendor = PCI_VENDOR_ID_WCHCN,
+ .device = PCI_DEVICE_ID_WCHCN_CH353_2S1PF,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup,
},
/* WCH CH352 2S card (16550 clone) */
{
- .vendor = PCI_VENDOR_ID_WCH,
- .device = PCI_DEVICE_ID_WCH_CH352_2S,
+ .vendor = PCI_VENDOR_ID_WCHCN,
+ .device = PCI_DEVICE_ID_WCHCN_CH352_2S,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch353_setup,
},
/* WCH CH355 4S card (16550 clone) */
{
- .vendor = PCI_VENDOR_ID_WCH,
- .device = PCI_DEVICE_ID_WCH_CH355_4S,
+ .vendor = PCI_VENDOR_ID_WCHCN,
+ .device = PCI_DEVICE_ID_WCHCN_CH355_4S,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch355_setup,
},
/* WCH CH382 2S card (16850 clone) */
{
- .vendor = PCIE_VENDOR_ID_WCH,
- .device = PCIE_DEVICE_ID_WCH_CH382_2S,
+ .vendor = PCI_VENDOR_ID_WCHIC,
+ .device = PCI_DEVICE_ID_WCHIC_CH382_2S,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch38x_setup,
},
/* WCH CH382 2S1P card (16850 clone) */
{
- .vendor = PCIE_VENDOR_ID_WCH,
- .device = PCIE_DEVICE_ID_WCH_CH382_2S1P,
+ .vendor = PCI_VENDOR_ID_WCHIC,
+ .device = PCI_DEVICE_ID_WCHIC_CH382_2S1P,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch38x_setup,
},
/* WCH CH384 4S card (16850 clone) */
{
- .vendor = PCIE_VENDOR_ID_WCH,
- .device = PCIE_DEVICE_ID_WCH_CH384_4S,
+ .vendor = PCI_VENDOR_ID_WCHIC,
+ .device = PCI_DEVICE_ID_WCHIC_CH384_4S,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.setup = pci_wch_ch38x_setup,
},
/* WCH CH384 8S card (16850 clone) */
{
- .vendor = PCIE_VENDOR_ID_WCH,
- .device = PCIE_DEVICE_ID_WCH_CH384_8S,
+ .vendor = PCI_VENDOR_ID_WCHIC,
+ .device = PCI_DEVICE_ID_WCHIC_CH384_8S,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.init = pci_wch_ch38x_init,
@@ -3916,11 +3977,11 @@ static const struct pci_device_id blacklist[] = {
/* multi-io cards handled by parport_serial */
/* WCH CH353 2S1P */
- { PCI_DEVICE(0x4348, 0x7053), 0, 0, REPORT_CONFIG(PARPORT_SERIAL), },
+ { PCI_VDEVICE(WCHCN, 0x7053), REPORT_CONFIG(PARPORT_SERIAL), },
/* WCH CH353 1S1P */
- { PCI_DEVICE(0x4348, 0x5053), 0, 0, REPORT_CONFIG(PARPORT_SERIAL), },
+ { PCI_VDEVICE(WCHCN, 0x5053), REPORT_CONFIG(PARPORT_SERIAL), },
/* WCH CH382 2S1P */
- { PCI_DEVICE(0x1c00, 0x3250), 0, 0, REPORT_CONFIG(PARPORT_SERIAL), },
+ { PCI_VDEVICE(WCHIC, 0x3250), REPORT_CONFIG(PARPORT_SERIAL), },
/* Intel platforms with MID UART */
{ PCI_VDEVICE(INTEL, 0x081b), REPORT_8250_CONFIG(MID), },
@@ -4108,7 +4169,7 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES);
} else {
pci_dbg(dev, "Using legacy interrupts\n");
- rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_LEGACY);
+ rc = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_INTX);
}
if (rc < 0) {
kfree(priv);
@@ -5208,6 +5269,14 @@ static const struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_2_115200 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0BA2,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_b2_2_115200 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0BA3,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_b2_2_115200 },
/*
* Brainboxes UC-235/246
*/
@@ -5328,6 +5397,14 @@ static const struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_b2_4_115200 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0C42,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_b2_4_115200 },
+ { PCI_VENDOR_ID_INTASHIELD, 0x0C43,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_b2_4_115200 },
/*
* Brainboxes UC-420
*/
@@ -5554,6 +5631,20 @@ static const struct pci_device_id serial_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID,
0, 0,
pbn_oxsemi_1_15625000 },
+ /*
+ * Brainboxes XC-235
+ */
+ { PCI_VENDOR_ID_INTASHIELD, 0x4026,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_oxsemi_1_15625000 },
+ /*
+ * Brainboxes XC-475
+ */
+ { PCI_VENDOR_ID_INTASHIELD, 0x4021,
+ PCI_ANY_ID, PCI_ANY_ID,
+ 0, 0,
+ pbn_oxsemi_1_15625000 },
/*
* Perle PCI-RAS cards
@@ -5993,27 +6084,27 @@ static const struct pci_device_id serial_pci_tbl[] = {
* WCH CH353 series devices: The 2S1P is handled by parport_serial
* so not listed here.
*/
- { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_4S,
+ { PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH353_4S,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_b0_bt_4_115200 },
- { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH353_2S1PF,
+ { PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH353_2S1PF,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_b0_bt_2_115200 },
- { PCI_VENDOR_ID_WCH, PCI_DEVICE_ID_WCH_CH355_4S,
+ { PCI_VENDOR_ID_WCHCN, PCI_DEVICE_ID_WCHCN_CH355_4S,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_b0_bt_4_115200 },
- { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S,
+ { PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH382_2S,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_wch382_2 },
- { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S,
+ { PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH384_4S,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_wch384_4 },
- { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_8S,
+ { PCI_VENDOR_ID_WCHIC, PCI_DEVICE_ID_WCHIC_CH384_8S,
PCI_ANY_ID, PCI_ANY_ID,
0, 0, pbn_wch384_8 },
/*
@@ -6129,4 +6220,4 @@ module_pci_driver(serial_pci_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module");
MODULE_DEVICE_TABLE(pci, serial_pci_tbl);
-MODULE_IMPORT_NS(SERIAL_8250_PCI);
+MODULE_IMPORT_NS("SERIAL_8250_PCI");
diff --git a/drivers/tty/serial/8250/8250_pci1xxxx.c b/drivers/tty/serial/8250/8250_pci1xxxx.c
index 2fbb5851f788..e9c51d4e447d 100644
--- a/drivers/tty/serial/8250/8250_pci1xxxx.c
+++ b/drivers/tty/serial/8250/8250_pci1xxxx.c
@@ -78,6 +78,12 @@
#define UART_TX_BYTE_FIFO 0x00
#define UART_FIFO_CTL 0x02
+#define UART_MODEM_CTL_REG 0x04
+#define UART_MODEM_CTL_RTS_SET BIT(1)
+
+#define UART_LINE_STAT_REG 0x05
+#define UART_LINE_XMIT_CHECK_MASK GENMASK(6, 5)
+
#define UART_ACTV_REG 0x11
#define UART_BLOCK_SET_ACTIVE BIT(0)
@@ -94,6 +100,7 @@
#define UART_BIT_SAMPLE_CNT_16 16
#define BAUD_CLOCK_DIV_INT_MSK GENMASK(31, 8)
#define ADCL_CFG_RTS_DELAY_MASK GENMASK(11, 8)
+#define FRAC_DIV_TX_END_POINT_MASK GENMASK(23, 20)
#define UART_WAKE_REG 0x8C
#define UART_WAKE_MASK_REG 0x90
@@ -134,6 +141,11 @@
#define UART_BST_STAT_LSR_FRAME_ERR 0x8000000
#define UART_BST_STAT_LSR_THRE 0x20000000
+#define GET_MODEM_CTL_RTS_STATUS(reg) ((reg) & UART_MODEM_CTL_RTS_SET)
+#define GET_RTS_PIN_STATUS(val) (((val) & TIOCM_RTS) >> 1)
+#define RTS_TOGGLE_STATUS_MASK(val, reg) (GET_MODEM_CTL_RTS_STATUS(reg) \
+ != GET_RTS_PIN_STATUS(val))
+
struct pci1xxxx_8250 {
unsigned int nr;
u8 dev_rev;
@@ -254,6 +266,47 @@ static void pci1xxxx_set_divisor(struct uart_port *port, unsigned int baud,
port->membase + UART_BAUD_CLK_DIVISOR_REG);
}
+static void pci1xxxx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ u32 fract_div_cfg_reg;
+ u32 line_stat_reg;
+ u32 modem_ctl_reg;
+ u32 adcl_cfg_reg;
+
+ adcl_cfg_reg = readl(port->membase + ADCL_CFG_REG);
+
+ /* HW is responsible in ADCL_EN case */
+ if ((adcl_cfg_reg & (ADCL_CFG_EN | ADCL_CFG_PIN_SEL)))
+ return;
+
+ modem_ctl_reg = readl(port->membase + UART_MODEM_CTL_REG);
+
+ serial8250_do_set_mctrl(port, mctrl);
+
+ if (RTS_TOGGLE_STATUS_MASK(mctrl, modem_ctl_reg)) {
+ line_stat_reg = readl(port->membase + UART_LINE_STAT_REG);
+ if (line_stat_reg & UART_LINE_XMIT_CHECK_MASK) {
+ fract_div_cfg_reg = readl(port->membase +
+ FRAC_DIV_CFG_REG);
+
+ writel((fract_div_cfg_reg &
+ ~(FRAC_DIV_TX_END_POINT_MASK)),
+ port->membase + FRAC_DIV_CFG_REG);
+
+ /* Enable ADC and set the nRTS pin */
+ writel((adcl_cfg_reg | (ADCL_CFG_EN |
+ ADCL_CFG_PIN_SEL)),
+ port->membase + ADCL_CFG_REG);
+
+ /* Revert to the original settings */
+ writel(adcl_cfg_reg, port->membase + ADCL_CFG_REG);
+
+ writel(fract_div_cfg_reg, port->membase +
+ FRAC_DIV_CFG_REG);
+ }
+ }
+}
+
static int pci1xxxx_rs485_config(struct uart_port *port,
struct ktermios *termios,
struct serial_rs485 *rs485)
@@ -382,10 +435,10 @@ static void pci1xxxx_rx_burst(struct uart_port *port, u32 uart_status)
}
static void pci1xxxx_process_write_data(struct uart_port *port,
- struct circ_buf *xmit,
int *data_empty_count,
u32 *valid_byte_count)
{
+ struct tty_port *tport = &port->state->port;
u32 valid_burst_count = *valid_byte_count / UART_BURST_SIZE;
/*
@@ -395,41 +448,36 @@ static void pci1xxxx_process_write_data(struct uart_port *port,
* one byte at a time.
*/
while (valid_burst_count) {
+ u32 c;
+
if (*data_empty_count - UART_BURST_SIZE < 0)
break;
- if (xmit->tail > (UART_XMIT_SIZE - UART_BURST_SIZE))
+ if (kfifo_len(&tport->xmit_fifo) < UART_BURST_SIZE)
+ break;
+ if (WARN_ON(kfifo_out(&tport->xmit_fifo, (u8 *)&c, sizeof(c)) !=
+ sizeof(c)))
break;
- writel(*(unsigned int *)&xmit->buf[xmit->tail],
- port->membase + UART_TX_BURST_FIFO);
+ writel(c, port->membase + UART_TX_BURST_FIFO);
*valid_byte_count -= UART_BURST_SIZE;
*data_empty_count -= UART_BURST_SIZE;
valid_burst_count -= UART_BYTE_SIZE;
-
- xmit->tail = (xmit->tail + UART_BURST_SIZE) &
- (UART_XMIT_SIZE - 1);
}
while (*valid_byte_count) {
- if (*data_empty_count - UART_BYTE_SIZE < 0)
+ u8 c;
+
+ if (!kfifo_get(&tport->xmit_fifo, &c))
break;
- writeb(xmit->buf[xmit->tail], port->membase +
- UART_TX_BYTE_FIFO);
+ writeb(c, port->membase + UART_TX_BYTE_FIFO);
*data_empty_count -= UART_BYTE_SIZE;
*valid_byte_count -= UART_BYTE_SIZE;
/*
- * When the tail of the circular buffer is reached, the next
- * byte is transferred to the beginning of the buffer.
- */
- xmit->tail = (xmit->tail + UART_BYTE_SIZE) &
- (UART_XMIT_SIZE - 1);
-
- /*
* If there are any pending burst count, data is handled by
* transmitting DWORDs at a time.
*/
- if (valid_burst_count && (xmit->tail <
- (UART_XMIT_SIZE - UART_BURST_SIZE)))
+ if (valid_burst_count &&
+ kfifo_len(&tport->xmit_fifo) >= UART_BURST_SIZE)
break;
}
}
@@ -437,11 +485,9 @@ static void pci1xxxx_process_write_data(struct uart_port *port,
static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status)
{
struct uart_8250_port *up = up_to_u8250p(port);
+ struct tty_port *tport = &port->state->port;
u32 valid_byte_count;
int data_empty_count;
- struct circ_buf *xmit;
-
- xmit = &port->state->xmit;
if (port->x_char) {
writeb(port->x_char, port->membase + UART_TX);
@@ -450,25 +496,25 @@ static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status)
return;
}
- if ((uart_tx_stopped(port)) || (uart_circ_empty(xmit))) {
+ if ((uart_tx_stopped(port)) || kfifo_is_empty(&tport->xmit_fifo)) {
port->ops->stop_tx(port);
} else {
data_empty_count = (pci1xxxx_read_burst_status(port) &
UART_BST_STAT_TX_COUNT_MASK) >> 8;
do {
- valid_byte_count = uart_circ_chars_pending(xmit);
+ valid_byte_count = kfifo_len(&tport->xmit_fifo);
- pci1xxxx_process_write_data(port, xmit,
+ pci1xxxx_process_write_data(port,
&data_empty_count,
&valid_byte_count);
port->icount.tx++;
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
break;
} while (data_empty_count && valid_byte_count);
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
/*
@@ -476,7 +522,8 @@ static void pci1xxxx_tx_burst(struct uart_port *port, u32 uart_status)
* the HW can go idle. So we get here once again with empty FIFO and
* disable the interrupt and RPM in __stop_tx()
*/
- if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
+ if (kfifo_is_empty(&tport->xmit_fifo) &&
+ !(up->capabilities & UART_CAP_RPM))
port->ops->stop_tx(port);
}
@@ -637,9 +684,14 @@ static int pci1xxxx_setup(struct pci_dev *pdev,
port->port.rs485_config = pci1xxxx_rs485_config;
port->port.rs485_supported = pci1xxxx_rs485_supported;
- /* From C0 rev Burst operation is supported */
+ /*
+ * C0 and later revisions support Burst operation.
+ * RTS workaround in mctrl is applicable only to B0.
+ */
if (rev >= 0xC0)
port->port.handle_irq = pci1xxxx_handle_irq;
+ else if (rev == 0xB0)
+ port->port.set_mctrl = pci1xxxx_set_mctrl;
ret = serial8250_pci_setup_port(pdev, port, 0, PORT_OFFSET * port_idx, 0);
if (ret < 0)
@@ -818,7 +870,7 @@ module_pci_driver(pci1xxxx_pci_driver);
static_assert((ARRAY_SIZE(logical_to_physical_port_idx) == PCI_SUBDEVICE_ID_EFAR_PCI1XXXX_1p3 + 1));
-MODULE_IMPORT_NS(SERIAL_8250_PCI);
+MODULE_IMPORT_NS("SERIAL_8250_PCI");
MODULE_DESCRIPTION("Microchip Technology Inc. PCIe to UART module");
MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>");
MODULE_AUTHOR("Tharun Kumar P <tharunkumar.pasumarthi@microchip.com>");
diff --git a/drivers/tty/serial/8250/8250_pcilib.c b/drivers/tty/serial/8250/8250_pcilib.c
index d234e9194feb..d8d0ae0d7238 100644
--- a/drivers/tty/serial/8250/8250_pcilib.c
+++ b/drivers/tty/serial/8250/8250_pcilib.c
@@ -12,6 +12,15 @@
#include "8250.h"
#include "8250_pcilib.h"
+int serial_8250_warn_need_ioport(struct pci_dev *dev)
+{
+ dev_warn(&dev->dev,
+ "Serial port not supported because of missing I/O resource\n");
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_NS_GPL(serial_8250_warn_need_ioport, "SERIAL_8250_PCI");
+
int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port,
u8 bar, unsigned int offset, int regshift)
{
@@ -27,14 +36,17 @@ int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port,
port->port.mapbase = pci_resource_start(dev, bar) + offset;
port->port.membase = pcim_iomap_table(dev)[bar] + offset;
port->port.regshift = regshift;
- } else {
+ } else if (IS_ENABLED(CONFIG_HAS_IOPORT)) {
port->port.iotype = UPIO_PORT;
port->port.iobase = pci_resource_start(dev, bar) + offset;
port->port.mapbase = 0;
port->port.membase = NULL;
port->port.regshift = 0;
+ } else {
+ return serial_8250_warn_need_ioport(dev);
}
return 0;
}
-EXPORT_SYMBOL_NS_GPL(serial8250_pci_setup_port, SERIAL_8250_PCI);
+EXPORT_SYMBOL_NS_GPL(serial8250_pci_setup_port, "SERIAL_8250_PCI");
+MODULE_DESCRIPTION("8250 PCI library");
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_pcilib.h b/drivers/tty/serial/8250/8250_pcilib.h
index 1aaf1b50ce9c..16a274574cde 100644
--- a/drivers/tty/serial/8250/8250_pcilib.h
+++ b/drivers/tty/serial/8250/8250_pcilib.h
@@ -13,3 +13,5 @@ struct uart_8250_port;
int serial8250_pci_setup_port(struct pci_dev *dev, struct uart_8250_port *port, u8 bar,
unsigned int offset, int regshift);
+
+int serial_8250_warn_need_ioport(struct pci_dev *dev);
diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c
new file mode 100644
index 000000000000..c0343bfb8064
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_platform.c
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Universal/legacy platform driver for 8250/16550-type serial ports
+ *
+ * Supports:
+ * ISA-compatible 8250/16550 ports
+ * ACPI 8250/16550 ports
+ * PNP 8250/16550 ports
+ * "serial8250" platform devices
+ */
+#include <linux/acpi.h>
+#include <linux/array_size.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/once.h>
+#include <linux/platform_device.h>
+
+#include <linux/serial_8250.h>
+
+#ifdef CONFIG_SPARC
+#include <linux/sunserialcore.h>
+#endif
+
+#include "8250.h"
+
+/*
+ * Configuration:
+ * share_irqs: Whether we pass IRQF_SHARED to request_irq().
+ * This option is unsafe when used on edge-triggered interrupts.
+ * skip_txen_test: Force skip of txen test at init time.
+ */
+unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
+unsigned int skip_txen_test;
+
+unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
+
+#include <asm/serial.h>
+
+/*
+ * SERIAL_PORT_DFNS tells us about built-in ports that have no
+ * standard enumeration mechanism. Platforms that can find all
+ * serial ports via mechanisms like ACPI or PCI need not supply it.
+ */
+#ifndef SERIAL_PORT_DFNS
+#define SERIAL_PORT_DFNS
+#endif
+
+static const struct old_serial_port old_serial_port[] = {
+ SERIAL_PORT_DFNS /* defined in asm/serial.h */
+};
+
+serial8250_isa_config_fn serial8250_isa_config;
+void serial8250_set_isa_configurator(serial8250_isa_config_fn v)
+{
+ serial8250_isa_config = v;
+}
+EXPORT_SYMBOL(serial8250_set_isa_configurator);
+
+static void __init __serial8250_isa_init_ports(void)
+{
+ int i, irqflag = 0;
+
+ if (nr_uarts > UART_NR)
+ nr_uarts = UART_NR;
+
+ /*
+ * Set up initial ISA ports based on nr_uart module param, or else
+ * default to CONFIG_SERIAL_8250_RUNTIME_UARTS. Note that we do not
+ * need to increase nr_uarts when setting up the initial ISA ports.
+ */
+ for (i = 0; i < nr_uarts; i++)
+ serial8250_setup_port(i);
+
+ /* chain base port ops to support Remote Supervisor Adapter */
+ univ8250_port_ops = *univ8250_port_base_ops;
+ univ8250_rsa_support(&univ8250_port_ops);
+
+ if (share_irqs)
+ irqflag = IRQF_SHARED;
+
+ for (i = 0; i < ARRAY_SIZE(old_serial_port) && i < nr_uarts; i++) {
+ struct uart_8250_port *up = serial8250_get_port(i);
+ struct uart_port *port = &up->port;
+
+ port->iobase = old_serial_port[i].port;
+ port->irq = irq_canonicalize(old_serial_port[i].irq);
+ port->irqflags = 0;
+ port->uartclk = old_serial_port[i].baud_base * 16;
+ port->flags = old_serial_port[i].flags;
+ port->hub6 = 0;
+ port->membase = old_serial_port[i].iomem_base;
+ port->iotype = old_serial_port[i].io_type;
+ port->regshift = old_serial_port[i].iomem_reg_shift;
+
+ port->irqflags |= irqflag;
+ if (serial8250_isa_config != NULL)
+ serial8250_isa_config(i, &up->port, &up->capabilities);
+ }
+}
+
+void __init serial8250_isa_init_ports(void)
+{
+ DO_ONCE(__serial8250_isa_init_ports);
+}
+
+/*
+ * Generic 16550A platform devices
+ */
+static int serial8250_probe_acpi(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uart_8250_port uart = { };
+ struct resource *regs;
+ int ret, line;
+
+ regs = platform_get_mem_or_io(pdev, 0);
+ if (!regs)
+ return dev_err_probe(dev, -EINVAL, "no registers defined\n");
+
+ switch (resource_type(regs)) {
+ case IORESOURCE_IO:
+ uart.port.iobase = regs->start;
+ break;
+ case IORESOURCE_MEM:
+ uart.port.mapbase = regs->start;
+ uart.port.mapsize = resource_size(regs);
+ uart.port.flags = UPF_IOREMAP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* default clock frequency */
+ uart.port.uartclk = 1843200;
+ uart.port.type = PORT_16550A;
+ uart.port.dev = &pdev->dev;
+ uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+
+ ret = uart_read_and_validate_port_properties(&uart.port);
+ /* no interrupt -> fall back to polling */
+ if (ret == -ENXIO)
+ ret = 0;
+ if (ret)
+ return ret;
+
+ line = serial8250_register_8250_port(&uart);
+ if (line < 0)
+ return line;
+
+ return 0;
+}
+
+static int serial8250_probe_platform(struct platform_device *dev, struct plat_serial8250_port *p)
+{
+ struct uart_8250_port uart;
+ int ret, i, irqflag = 0;
+
+ memset(&uart, 0, sizeof(uart));
+
+ if (share_irqs)
+ irqflag = IRQF_SHARED;
+
+ for (i = 0; p && p->flags != 0; p++, i++) {
+ uart.port.iobase = p->iobase;
+ uart.port.membase = p->membase;
+ uart.port.irq = p->irq;
+ uart.port.irqflags = p->irqflags;
+ uart.port.uartclk = p->uartclk;
+ uart.port.regshift = p->regshift;
+ uart.port.iotype = p->iotype;
+ uart.port.flags = p->flags;
+ uart.port.mapbase = p->mapbase;
+ uart.port.mapsize = p->mapsize;
+ uart.port.hub6 = p->hub6;
+ uart.port.has_sysrq = p->has_sysrq;
+ uart.port.private_data = p->private_data;
+ uart.port.type = p->type;
+ uart.bugs = p->bugs;
+ uart.port.serial_in = p->serial_in;
+ uart.port.serial_out = p->serial_out;
+ uart.dl_read = p->dl_read;
+ uart.dl_write = p->dl_write;
+ uart.port.handle_irq = p->handle_irq;
+ uart.port.handle_break = p->handle_break;
+ uart.port.set_termios = p->set_termios;
+ uart.port.set_ldisc = p->set_ldisc;
+ uart.port.get_mctrl = p->get_mctrl;
+ uart.port.pm = p->pm;
+ uart.port.dev = &dev->dev;
+ uart.port.irqflags |= irqflag;
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0) {
+ dev_err(&dev->dev, "unable to register port at index %d "
+ "(IO%lx MEM%llx IRQ%d): %d\n", i,
+ p->iobase, (unsigned long long)p->mapbase,
+ p->irq, ret);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Register a set of serial devices attached to a platform device.
+ * The list is terminated with a zero flags entry, which means we expect
+ * all entries to have at least UPF_BOOT_AUTOCONF set.
+ */
+static int serial8250_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct plat_serial8250_port *p;
+
+ p = dev_get_platdata(dev);
+ if (p)
+ return serial8250_probe_platform(pdev, p);
+
+ /*
+ * Probe platform UART devices defined using standard hardware
+ * discovery mechanism like ACPI or DT. Support only ACPI based
+ * serial device for now.
+ */
+ if (has_acpi_companion(dev))
+ return serial8250_probe_acpi(pdev);
+
+ return 0;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static void serial8250_remove(struct platform_device *dev)
+{
+ int i;
+
+ for (i = 0; i < nr_uarts; i++) {
+ struct uart_8250_port *up = serial8250_get_port(i);
+
+ if (up->port.dev == &dev->dev)
+ serial8250_unregister_port(i);
+ }
+}
+
+static int serial8250_suspend(struct platform_device *dev, pm_message_t state)
+{
+ int i;
+
+ for (i = 0; i < UART_NR; i++) {
+ struct uart_8250_port *up = serial8250_get_port(i);
+
+ if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+ uart_suspend_port(&serial8250_reg, &up->port);
+ }
+
+ return 0;
+}
+
+static int serial8250_resume(struct platform_device *dev)
+{
+ int i;
+
+ for (i = 0; i < UART_NR; i++) {
+ struct uart_8250_port *up = serial8250_get_port(i);
+
+ if (up->port.type != PORT_UNKNOWN && up->port.dev == &dev->dev)
+ serial8250_resume_port(i);
+ }
+
+ return 0;
+}
+
+static const struct acpi_device_id acpi_platform_serial_table[] = {
+ { "RSCV0003" }, /* RISC-V Generic 16550A UART */
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, acpi_platform_serial_table);
+
+static struct platform_driver serial8250_isa_driver = {
+ .probe = serial8250_probe,
+ .remove = serial8250_remove,
+ .suspend = serial8250_suspend,
+ .resume = serial8250_resume,
+ .driver = {
+ .name = "serial8250",
+ .acpi_match_table = acpi_platform_serial_table,
+ },
+};
+
+/*
+ * This "device" covers _all_ ISA 8250-compatible serial devices listed
+ * in the table in include/asm/serial.h.
+ */
+struct platform_device *serial8250_isa_devs;
+
+static int __init serial8250_init(void)
+{
+ int ret;
+
+ if (nr_uarts == 0)
+ return -ENODEV;
+
+ serial8250_isa_init_ports();
+
+ pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %s\n",
+ nr_uarts, str_enabled_disabled(share_irqs));
+
+#ifdef CONFIG_SPARC
+ ret = sunserial_register_minors(&serial8250_reg, UART_NR);
+#else
+ serial8250_reg.nr = UART_NR;
+ ret = uart_register_driver(&serial8250_reg);
+#endif
+ if (ret)
+ goto out;
+
+ ret = serial8250_pnp_init();
+ if (ret)
+ goto unreg_uart_drv;
+
+ serial8250_isa_devs = platform_device_alloc("serial8250", PLAT8250_DEV_LEGACY);
+ if (!serial8250_isa_devs) {
+ ret = -ENOMEM;
+ goto unreg_pnp;
+ }
+
+ ret = platform_device_add(serial8250_isa_devs);
+ if (ret)
+ goto put_dev;
+
+ serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
+
+ ret = platform_driver_register(&serial8250_isa_driver);
+ if (ret == 0)
+ goto out;
+
+ platform_device_del(serial8250_isa_devs);
+put_dev:
+ platform_device_put(serial8250_isa_devs);
+unreg_pnp:
+ serial8250_pnp_exit();
+unreg_uart_drv:
+#ifdef CONFIG_SPARC
+ sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
+ uart_unregister_driver(&serial8250_reg);
+#endif
+out:
+ return ret;
+}
+module_init(serial8250_init);
+
+static void __exit serial8250_exit(void)
+{
+ struct platform_device *isa_dev = serial8250_isa_devs;
+
+ /*
+ * This tells serial8250_unregister_port() not to re-register
+ * the ports (thereby making serial8250_isa_driver permanently
+ * in use).
+ */
+ serial8250_isa_devs = NULL;
+
+ platform_driver_unregister(&serial8250_isa_driver);
+ platform_device_unregister(isa_dev);
+
+ serial8250_pnp_exit();
+
+#ifdef CONFIG_SPARC
+ sunserial_unregister_minors(&serial8250_reg, UART_NR);
+#else
+ uart_unregister_driver(&serial8250_reg);
+#endif
+}
+module_exit(serial8250_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic 8250/16x50 serial platform driver");
+
+module_param_hw(share_irqs, uint, other, 0644);
+MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices (unsafe)");
+
+module_param(nr_uarts, uint, 0644);
+MODULE_PARM_DESC(nr_uarts, "Maximum number of UARTs supported. (1-" __MODULE_STRING(CONFIG_SERIAL_8250_NR_UARTS) ")");
+
+module_param(skip_txen_test, uint, 0644);
+MODULE_PARM_DESC(skip_txen_test, "Skip checking for the TXEN bug at init time");
+
+MODULE_ALIAS_CHARDEV_MAJOR(TTY_MAJOR);
+
+#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
+#ifndef MODULE
+/*
+ * This module was renamed to 8250_core in 3.7. Keep the old "8250" name
+ * working as well for the module options so we don't break people. We
+ * need to keep the names identical and the convenient macros will happily
+ * refuse to let us do that by failing the build with redefinition errors
+ * of global variables. So we stick them inside a dummy function to avoid
+ * those conflicts. The options still get parsed, and the redefined
+ * MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
+ *
+ * This is hacky. I'm sorry.
+ */
+static void __used s8250_options(void)
+{
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "8250_core."
+
+ module_param_cb(share_irqs, &param_ops_uint, &share_irqs, 0644);
+ module_param_cb(nr_uarts, &param_ops_uint, &nr_uarts, 0644);
+ module_param_cb(skip_txen_test, &param_ops_uint, &skip_txen_test, 0644);
+}
+#else
+MODULE_ALIAS("8250_core");
+#endif
+#endif
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 1974bbadc975..7a837fdf9df1 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -10,6 +10,7 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pm.h>
#include <linux/pnp.h>
#include <linux/string.h>
#include <linux/kernel.h>
@@ -434,7 +435,8 @@ static int
serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{
struct uart_8250_port uart, *port;
- int ret, line, flags = dev_id->driver_data;
+ int ret, flags = dev_id->driver_data;
+ long line;
if (flags & UNKNOWN_DEV) {
ret = serial_pnp_guess_board(dev);
@@ -443,37 +445,37 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
}
memset(&uart, 0, sizeof(uart));
- if (pnp_irq_valid(dev, 0))
- uart.port.irq = pnp_irq(dev, 0);
if ((flags & CIR_PORT) && pnp_port_valid(dev, 2)) {
uart.port.iobase = pnp_port_start(dev, 2);
- uart.port.iotype = UPIO_PORT;
} else if (pnp_port_valid(dev, 0)) {
uart.port.iobase = pnp_port_start(dev, 0);
- uart.port.iotype = UPIO_PORT;
} else if (pnp_mem_valid(dev, 0)) {
uart.port.mapbase = pnp_mem_start(dev, 0);
- uart.port.iotype = UPIO_MEM;
+ uart.port.mapsize = pnp_mem_len(dev, 0);
uart.port.flags = UPF_IOREMAP;
} else
return -ENODEV;
- dev_dbg(&dev->dev,
- "Setup PNP port: port %#lx, mem %#llx, irq %u, type %u\n",
- uart.port.iobase, (unsigned long long)uart.port.mapbase,
- uart.port.irq, uart.port.iotype);
+ uart.port.uartclk = 1843200;
+ uart.port.dev = &dev->dev;
+ uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+
+ ret = uart_read_port_properties(&uart.port);
+ /* no interrupt -> fall back to polling */
+ if (ret == -ENXIO)
+ ret = 0;
+ if (ret)
+ return ret;
if (flags & CIR_PORT) {
uart.port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE;
uart.port.type = PORT_8250_CIR;
}
- uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
- if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
- uart.port.flags |= UPF_SHARE_IRQ;
- uart.port.uartclk = 1843200;
- device_property_read_u32(&dev->dev, "clock-frequency", &uart.port.uartclk);
- uart.port.dev = &dev->dev;
+ dev_dbg(&dev->dev,
+ "Setup PNP port: port %#lx, mem %#llx, size %#llx, irq %u, type %u\n",
+ uart.port.iobase, (unsigned long long)uart.port.mapbase,
+ (unsigned long long)uart.port.mapsize, uart.port.irq, uart.port.iotype);
line = serial8250_register_8250_port(&uart);
if (line < 0 || (flags & CIR_PORT))
@@ -483,7 +485,7 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
if (uart_console(&port->port))
dev->capabilities |= PNP_CONSOLE;
- pnp_set_drvdata(dev, (void *)((long)line + 1));
+ pnp_set_drvdata(dev, (void *)line);
return 0;
}
@@ -492,38 +494,33 @@ static void serial_pnp_remove(struct pnp_dev *dev)
long line = (long)pnp_get_drvdata(dev);
dev->capabilities &= ~PNP_CONSOLE;
- if (line)
- serial8250_unregister_port(line - 1);
+ serial8250_unregister_port(line);
}
-static int __maybe_unused serial_pnp_suspend(struct device *dev)
+static int serial_pnp_suspend(struct device *dev)
{
long line = (long)dev_get_drvdata(dev);
- if (!line)
- return -ENODEV;
- serial8250_suspend_port(line - 1);
+ serial8250_suspend_port(line);
return 0;
}
-static int __maybe_unused serial_pnp_resume(struct device *dev)
+static int serial_pnp_resume(struct device *dev)
{
long line = (long)dev_get_drvdata(dev);
- if (!line)
- return -ENODEV;
- serial8250_resume_port(line - 1);
+ serial8250_resume_port(line);
return 0;
}
-static SIMPLE_DEV_PM_OPS(serial_pnp_pm_ops, serial_pnp_suspend, serial_pnp_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(serial_pnp_pm_ops, serial_pnp_suspend, serial_pnp_resume);
static struct pnp_driver serial_pnp_driver = {
.name = "serial",
.probe = serial_pnp_probe,
.remove = serial_pnp_remove,
.driver = {
- .pm = &serial_pnp_pm_ops,
+ .pm = pm_sleep_ptr(&serial_pnp_pm_ops),
},
.id_table = pnp_dev_table,
};
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index fc9dd5d45295..8ac452cea36c 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -338,6 +338,7 @@ static void default_serial_dl_write(struct uart_8250_port *up, u32 value)
serial_out(up, UART_DLM, value >> 8 & 0xff);
}
+#ifdef CONFIG_HAS_IOPORT
static unsigned int hub6_serial_in(struct uart_port *p, int offset)
{
offset = offset << p->regshift;
@@ -351,6 +352,7 @@ static void hub6_serial_out(struct uart_port *p, int offset, int value)
outb(p->hub6 - 1 + offset, p->iobase);
outb(value, p->iobase + 1);
}
+#endif /* CONFIG_HAS_IOPORT */
static unsigned int mem_serial_in(struct uart_port *p, int offset)
{
@@ -400,6 +402,7 @@ static unsigned int mem32be_serial_in(struct uart_port *p, int offset)
return ioread32be(p->membase + offset);
}
+#ifdef CONFIG_HAS_IOPORT
static unsigned int io_serial_in(struct uart_port *p, int offset)
{
offset = offset << p->regshift;
@@ -411,6 +414,15 @@ static void io_serial_out(struct uart_port *p, int offset, int value)
offset = offset << p->regshift;
outb(value, p->iobase + offset);
}
+#endif
+static unsigned int no_serial_in(struct uart_port *p, int offset)
+{
+ return (unsigned int)-1;
+}
+
+static void no_serial_out(struct uart_port *p, int offset, int value)
+{
+}
static int serial8250_default_handle_irq(struct uart_port *port);
@@ -422,10 +434,12 @@ static void set_io_from_upio(struct uart_port *p)
up->dl_write = default_serial_dl_write;
switch (p->iotype) {
+#ifdef CONFIG_HAS_IOPORT
case UPIO_HUB6:
p->serial_in = hub6_serial_in;
p->serial_out = hub6_serial_out;
break;
+#endif
case UPIO_MEM:
p->serial_in = mem_serial_in;
@@ -446,11 +460,17 @@ static void set_io_from_upio(struct uart_port *p)
p->serial_in = mem32be_serial_in;
p->serial_out = mem32be_serial_out;
break;
-
- default:
+#ifdef CONFIG_HAS_IOPORT
+ case UPIO_PORT:
p->serial_in = io_serial_in;
p->serial_out = io_serial_out;
break;
+#endif
+ default:
+ WARN(p->iotype != UPIO_PORT || p->iobase,
+ "Unsupported UART type %x\n", p->iotype);
+ p->serial_in = no_serial_in;
+ p->serial_out = no_serial_out;
}
/* Remember loaded iotype */
up->cur_iotype = p->iotype;
@@ -546,19 +566,17 @@ static int serial8250_em485_init(struct uart_8250_port *p)
if (!p->em485)
return -ENOMEM;
- hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
- hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC,
- HRTIMER_MODE_REL);
- p->em485->stop_tx_timer.function = &serial8250_em485_handle_stop_tx;
- p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx;
+ hrtimer_setup(&p->em485->stop_tx_timer, &serial8250_em485_handle_stop_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ hrtimer_setup(&p->em485->start_tx_timer, &serial8250_em485_handle_start_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
p->em485->port = p;
p->em485->active_timer = NULL;
p->em485->tx_stopped = true;
deassert_rts:
if (p->em485->tx_stopped)
- p->rs485_stop_tx(p);
+ p->rs485_stop_tx(p, true);
return 0;
}
@@ -612,13 +630,6 @@ int serial8250_em485_config(struct uart_port *port, struct ktermios *termios,
{
struct uart_8250_port *up = up_to_u8250p(port);
- /* pick sane settings if the user hasn't */
- if (!!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
- !!(rs485->flags & SER_RS485_RTS_AFTER_SEND)) {
- rs485->flags |= SER_RS485_RTS_ON_SEND;
- rs485->flags &= ~SER_RS485_RTS_AFTER_SEND;
- }
-
/*
* Both serial8250_em485_init() and serial8250_em485_destroy()
* are idempotent.
@@ -1181,7 +1192,7 @@ static void autoconfig(struct uart_8250_port *up)
*/
scratch = serial_in(up, UART_IER);
serial_out(up, UART_IER, 0);
-#ifdef __i386__
+#if defined(__i386__) && defined(CONFIG_HAS_IOPORT)
outb(0xff, 0x080);
#endif
/*
@@ -1190,7 +1201,7 @@ static void autoconfig(struct uart_8250_port *up)
*/
scratch2 = serial_in(up, UART_IER) & UART_IER_ALL_INTR;
serial_out(up, UART_IER, UART_IER_ALL_INTR);
-#ifdef __i386__
+#if defined(__i386__) && defined(CONFIG_HAS_IOPORT)
outb(0, 0x080);
#endif
scratch3 = serial_in(up, UART_IER) & UART_IER_ALL_INTR;
@@ -1377,7 +1388,6 @@ static void serial8250_stop_rx(struct uart_port *port)
serial8250_rpm_get(up);
up->ier &= ~(UART_IER_RLSI | UART_IER_RDI);
- up->port.read_status_mask &= ~UART_LSR_DR;
serial_port_out(port, UART_IER, up->ier);
serial8250_rpm_put(up);
@@ -1386,10 +1396,11 @@ static void serial8250_stop_rx(struct uart_port *port)
/**
* serial8250_em485_stop_tx() - generic ->rs485_stop_tx() callback
* @p: uart 8250 port
+ * @toggle_ier: true to allow enabling receive interrupts
*
* Generic callback usable by 8250 uart drivers to stop rs485 transmission.
*/
-void serial8250_em485_stop_tx(struct uart_8250_port *p)
+void serial8250_em485_stop_tx(struct uart_8250_port *p, bool toggle_ier)
{
unsigned char mcr = serial8250_in_MCR(p);
@@ -1410,8 +1421,10 @@ void serial8250_em485_stop_tx(struct uart_8250_port *p)
if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
serial8250_clear_and_reinit_fifos(p);
- p->ier |= UART_IER_RLSI | UART_IER_RDI;
- serial_port_out(&p->port, UART_IER, p->ier);
+ if (toggle_ier) {
+ p->ier |= UART_IER_RLSI | UART_IER_RDI;
+ serial_port_out(&p->port, UART_IER, p->ier);
+ }
}
}
EXPORT_SYMBOL_GPL(serial8250_em485_stop_tx);
@@ -1426,7 +1439,7 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t)
serial8250_rpm_get(p);
uart_port_lock_irqsave(&p->port, &flags);
if (em485->active_timer == &em485->stop_tx_timer) {
- p->rs485_stop_tx(p);
+ p->rs485_stop_tx(p, true);
em485->active_timer = NULL;
em485->tx_stopped = true;
}
@@ -1458,7 +1471,7 @@ static void __stop_tx_rs485(struct uart_8250_port *p, u64 stop_delay)
em485->active_timer = &em485->stop_tx_timer;
hrtimer_start(&em485->stop_tx_timer, ns_to_ktime(stop_delay), HRTIMER_MODE_REL);
} else {
- p->rs485_stop_tx(p);
+ p->rs485_stop_tx(p, true);
em485->active_timer = NULL;
em485->tx_stopped = true;
}
@@ -1547,6 +1560,7 @@ static inline void __start_tx(struct uart_port *port)
/**
* serial8250_em485_start_tx() - generic ->rs485_start_tx() callback
* @up: uart 8250 port
+ * @toggle_ier: true to allow disabling receive interrupts
*
* Generic callback usable by 8250 uart drivers to start rs485 transmission.
* Assumes that setting the RTS bit in the MCR register means RTS is high.
@@ -1554,11 +1568,11 @@ static inline void __start_tx(struct uart_port *port)
* stoppable by disabling the UART_IER_RDI interrupt. (Some chips set the
* UART_LSR_DR bit even when UART_IER_RDI is disabled, foiling this approach.)
*/
-void serial8250_em485_start_tx(struct uart_8250_port *up)
+void serial8250_em485_start_tx(struct uart_8250_port *up, bool toggle_ier)
{
unsigned char mcr = serial8250_in_MCR(up);
- if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX))
+ if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX) && toggle_ier)
serial8250_stop_rx(&up->port);
if (up->port.rs485.flags & SER_RS485_RTS_ON_SEND)
@@ -1592,7 +1606,7 @@ static bool start_tx_rs485(struct uart_port *port)
if (em485->tx_stopped) {
em485->tx_stopped = false;
- up->rs485_start_tx(up);
+ up->rs485_start_tx(up, true);
if (up->port.rs485.delay_rts_before_send > 0) {
em485->active_timer = &em485->start_tx_timer;
@@ -1630,7 +1644,7 @@ static void serial8250_start_tx(struct uart_port *port)
/* Port locked to synchronize UART_IER access against the console. */
lockdep_assert_held_once(&port->lock);
- if (!port->x_char && uart_circ_empty(&port->state->xmit))
+ if (!port->x_char && kfifo_is_empty(&port->state->port.xmit_fifo))
return;
serial8250_rpm_get_tx(up);
@@ -1664,7 +1678,7 @@ static void serial8250_disable_ms(struct uart_port *port)
if (up->bugs & UART_BUG_NOMSR)
return;
- mctrl_gpio_disable_ms(up->gpios);
+ mctrl_gpio_disable_ms_no_sync(up->gpios);
up->ier &= ~UART_IER_MSI;
serial_port_out(port, UART_IER, up->ier);
@@ -1778,7 +1792,7 @@ EXPORT_SYMBOL_GPL(serial8250_rx_chars);
void serial8250_tx_chars(struct uart_8250_port *up)
{
struct uart_port *port = &up->port;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
int count;
if (port->x_char) {
@@ -1789,14 +1803,19 @@ void serial8250_tx_chars(struct uart_8250_port *up)
serial8250_stop_tx(port);
return;
}
- if (uart_circ_empty(xmit)) {
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
__stop_tx(up);
return;
}
count = up->tx_loadsz;
do {
- serial_out(up, UART_TX, xmit->buf[xmit->tail]);
+ unsigned char c;
+
+ if (!uart_fifo_get(port, &c))
+ break;
+
+ serial_out(up, UART_TX, c);
if (up->bugs & UART_BUG_TXRACE) {
/*
* The Aspeed BMC virtual UARTs have a bug where data
@@ -1809,9 +1828,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
*/
serial_in(up, UART_SCR);
}
- uart_xmit_advance(port, 1);
- if (uart_circ_empty(xmit))
- break;
+
if ((up->capabilities & UART_CAP_HFIFO) &&
!uart_lsr_tx_empty(serial_in(up, UART_LSR)))
break;
@@ -1821,7 +1838,7 @@ void serial8250_tx_chars(struct uart_8250_port *up)
break;
} while (--count > 0);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
/*
@@ -1829,7 +1846,8 @@ void serial8250_tx_chars(struct uart_8250_port *up)
* HW can go idle. So we get here once again with empty FIFO and disable
* the interrupt and RPM in __stop_tx()
*/
- if (uart_circ_empty(xmit) && !(up->capabilities & UART_CAP_RPM))
+ if (kfifo_is_empty(&tport->xmit_fifo) &&
+ !(up->capabilities & UART_CAP_RPM))
__stop_tx(up);
}
EXPORT_SYMBOL_GPL(serial8250_tx_chars);
@@ -1914,7 +1932,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
*/
if (!(status & (UART_LSR_FIFOE | UART_LSR_BRK_ERROR_BITS)) &&
(port->status & (UPSTAT_AUTOCTS | UPSTAT_AUTORTS)) &&
- !(port->read_status_mask & UART_LSR_DR))
+ !(up->ier & (UART_IER_RLSI | UART_IER_RDI)))
skip_rx = true;
if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) {
@@ -2062,11 +2080,20 @@ static void serial8250_break_ctl(struct uart_port *port, int break_state)
serial8250_rpm_put(up);
}
-static void wait_for_lsr(struct uart_8250_port *up, int bits)
+/* Returns true if @bits were set, false on timeout */
+static bool wait_for_lsr(struct uart_8250_port *up, int bits)
{
- unsigned int status, tmout = 10000;
+ unsigned int status, tmout;
+
+ /*
+ * Wait for a character to be sent. Fallback to a safe default
+ * timeout value if @frame_time is not available.
+ */
+ if (up->port.frame_time)
+ tmout = up->port.frame_time * 2 / NSEC_PER_USEC;
+ else
+ tmout = 10000;
- /* Wait up to 10ms for the character(s) to be sent. */
for (;;) {
status = serial_lsr_in(up);
@@ -2077,11 +2104,11 @@ static void wait_for_lsr(struct uart_8250_port *up, int bits)
udelay(1);
touch_nmi_watchdog();
}
+
+ return (tmout != 0);
}
-/*
- * Wait for transmitter & holding register to empty
- */
+/* Wait for transmitter and holding register to empty with timeout */
static void wait_for_xmitr(struct uart_8250_port *up, int bits)
{
unsigned int tmout;
@@ -2379,28 +2406,26 @@ int serial8250_do_startup(struct uart_port *port)
* test if we receive TX irq. This way, we'll never enable
* UART_BUG_TXEN.
*/
- if (up->port.quirks & UPQ_NO_TXEN_TEST)
- goto dont_test_tx_en;
-
- /*
- * Do a quick test to see if we receive an interrupt when we enable
- * the TX irq.
- */
- serial_port_out(port, UART_IER, UART_IER_THRI);
- lsr = serial_port_in(port, UART_LSR);
- iir = serial_port_in(port, UART_IIR);
- serial_port_out(port, UART_IER, 0);
+ if (!(up->port.quirks & UPQ_NO_TXEN_TEST)) {
+ /*
+ * Do a quick test to see if we receive an interrupt when we
+ * enable the TX irq.
+ */
+ serial_port_out(port, UART_IER, UART_IER_THRI);
+ lsr = serial_port_in(port, UART_LSR);
+ iir = serial_port_in(port, UART_IIR);
+ serial_port_out(port, UART_IER, 0);
- if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
- if (!(up->bugs & UART_BUG_TXEN)) {
- up->bugs |= UART_BUG_TXEN;
- dev_dbg(port->dev, "enabling bad tx status workarounds\n");
+ if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
+ if (!(up->bugs & UART_BUG_TXEN)) {
+ up->bugs |= UART_BUG_TXEN;
+ dev_dbg(port->dev, "enabling bad tx status workarounds\n");
+ }
+ } else {
+ up->bugs &= ~UART_BUG_TXEN;
}
- } else {
- up->bugs &= ~UART_BUG_TXEN;
}
-dont_test_tx_en:
uart_port_unlock_irqrestore(port, flags);
/*
@@ -2526,6 +2551,14 @@ static void serial8250_shutdown(struct uart_port *port)
serial8250_do_shutdown(port);
}
+static void serial8250_flush_buffer(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ if (up->dma)
+ serial8250_tx_dma_flush(up);
+}
+
static unsigned int serial8250_do_get_divisor(struct uart_port *port,
unsigned int baud,
unsigned int *frac)
@@ -2612,7 +2645,7 @@ static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
}
void serial8250_do_set_divisor(struct uart_port *port, unsigned int baud,
- unsigned int quot, unsigned int quot_frac)
+ unsigned int quot)
{
struct uart_8250_port *up = up_to_u8250p(port);
@@ -2644,7 +2677,7 @@ static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
if (port->set_divisor)
port->set_divisor(port, baud, quot, quot_frac);
else
- serial8250_do_set_divisor(port, baud, quot, quot_frac);
+ serial8250_do_set_divisor(port, baud, quot);
}
static unsigned int serial8250_get_baud_rate(struct uart_port *port,
@@ -2769,7 +2802,13 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
*/
uart_update_timeout(port, termios->c_cflag, baud);
- port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+ /*
+ * Specify which conditions may be considered for error
+ * handling and the ignoring of characters. The actual
+ * ignoring of characters only occurs if the bit is set
+ * in @ignore_status_mask as well.
+ */
+ port->read_status_mask = UART_LSR_OE | UART_LSR_DR;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
@@ -2927,7 +2966,6 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
{
unsigned int size = serial8250_port_size(up);
struct uart_port *port = &up->port;
- int ret = 0;
switch (port->iotype) {
case UPIO_AU:
@@ -2936,32 +2974,28 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_MEM32BE:
case UPIO_MEM16:
case UPIO_MEM:
- if (!port->mapbase) {
- ret = -EINVAL;
- break;
- }
+ if (!port->mapbase)
+ return -EINVAL;
- if (!request_mem_region(port->mapbase, size, "serial")) {
- ret = -EBUSY;
- break;
- }
+ if (!request_mem_region(port->mapbase, size, "serial"))
+ return -EBUSY;
if (port->flags & UPF_IOREMAP) {
port->membase = ioremap(port->mapbase, size);
if (!port->membase) {
release_mem_region(port->mapbase, size);
- ret = -ENOMEM;
+ return -ENOMEM;
}
}
- break;
-
+ return 0;
case UPIO_HUB6:
case UPIO_PORT:
if (!request_region(port->iobase, size, "serial"))
- ret = -EBUSY;
- break;
+ return -EBUSY;
+ return 0;
}
- return ret;
+
+ return 0;
}
static void serial8250_release_std_resource(struct uart_8250_port *up)
@@ -3179,7 +3213,7 @@ static void serial8250_config_port(struct uart_port *port, int flags)
static int
serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
{
- if (ser->irq >= nr_irqs || ser->irq < 0 ||
+ if (ser->irq >= irq_get_nr_irqs() || ser->irq < 0 ||
ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
ser->type >= ARRAY_SIZE(uart_config) || ser->type == PORT_CIRRUS ||
ser->type == PORT_STARTECH)
@@ -3209,6 +3243,7 @@ static const struct uart_ops serial8250_pops = {
.break_ctl = serial8250_break_ctl,
.startup = serial8250_startup,
.shutdown = serial8250_shutdown,
+ .flush_buffer = serial8250_flush_buffer,
.set_termios = serial8250_set_termios,
.set_ldisc = serial8250_set_ldisc,
.pm = serial8250_pm,
@@ -3233,7 +3268,7 @@ void serial8250_init_port(struct uart_8250_port *up)
port->ops = &serial8250_pops;
port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
- up->cur_iotype = 0xFF;
+ up->cur_iotype = UPIO_UNKNOWN;
}
EXPORT_SYMBOL_GPL(serial8250_init_port);
@@ -3268,10 +3303,15 @@ EXPORT_SYMBOL_GPL(serial8250_set_defaults);
static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
{
+ serial_port_out(port, UART_TX, ch);
+}
+
+static void serial8250_console_wait_putchar(struct uart_port *port, unsigned char ch)
+{
struct uart_8250_port *up = up_to_u8250p(port);
wait_for_xmitr(up, UART_LSR_THRE);
- serial_port_out(port, UART_TX, ch);
+ serial8250_console_putchar(port, ch);
}
/*
@@ -3300,6 +3340,16 @@ static void serial8250_console_restore(struct uart_8250_port *up)
serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
}
+static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ if (wait_for_lsr(up, UART_LSR_THRE))
+ return;
+ }
+}
+
/*
* Print a string to the serial port using the device FIFO
*
@@ -3309,24 +3359,34 @@ static void serial8250_console_restore(struct uart_8250_port *up)
static void serial8250_console_fifo_write(struct uart_8250_port *up,
const char *s, unsigned int count)
{
- int i;
const char *end = s + count;
unsigned int fifosize = up->tx_loadsz;
+ struct uart_port *port = &up->port;
+ unsigned int tx_count = 0;
bool cr_sent = false;
+ unsigned int i;
while (s != end) {
- wait_for_lsr(up, UART_LSR_THRE);
+ /* Allow timeout for each byte of a possibly full FIFO */
+ fifo_wait_for_lsr(up, fifosize);
for (i = 0; i < fifosize && s != end; ++i) {
if (*s == '\n' && !cr_sent) {
- serial_out(up, UART_TX, '\r');
+ serial8250_console_putchar(port, '\r');
cr_sent = true;
} else {
- serial_out(up, UART_TX, *s++);
+ serial8250_console_putchar(port, *s++);
cr_sent = false;
}
}
+ tx_count = i;
}
+
+ /*
+ * Allow timeout for each byte written since the caller will only wait
+ * for UART_LSR_BOTH_EMPTY using the timeout of a single character
+ */
+ fifo_wait_for_lsr(up, tx_count);
}
/*
@@ -3368,7 +3428,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
if (em485) {
if (em485->tx_stopped)
- up->rs485_start_tx(up);
+ up->rs485_start_tx(up, false);
mdelay(port->rs485.delay_rts_before_send);
}
@@ -3395,7 +3455,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
if (likely(use_fifo))
serial8250_console_fifo_write(up, s, count);
else
- uart_console_write(port, s, count, serial8250_console_putchar);
+ uart_console_write(port, s, count, serial8250_console_wait_putchar);
/*
* Finally, wait for transmitter to become empty
@@ -3406,7 +3466,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
if (em485) {
mdelay(port->rs485.delay_rts_after_send);
if (em485->tx_stopped)
- up->rs485_stop_tx(up);
+ up->rs485_stop_tx(up, false);
}
serial_port_out(port, UART_IER, ier);
@@ -3476,4 +3536,5 @@ int serial8250_console_exit(struct uart_port *port)
#endif /* CONFIG_SERIAL_8250_CONSOLE */
+MODULE_DESCRIPTION("Base port operations for 8250/16550-type serial ports");
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c
index f1a51b00b1b9..6dd0190b4843 100644
--- a/drivers/tty/serial/8250/8250_pxa.c
+++ b/drivers/tty/serial/8250/8250_pxa.c
@@ -125,6 +125,7 @@ static int serial_pxa_probe(struct platform_device *pdev)
uart.port.iotype = UPIO_MEM32;
uart.port.regshift = 2;
uart.port.fifosize = 64;
+ uart.tx_loadsz = 32;
uart.dl_write = serial_pxa_dl_write;
ret = serial8250_register_8250_port(&uart);
@@ -153,7 +154,7 @@ static void serial_pxa_remove(struct platform_device *pdev)
static struct platform_driver serial_pxa_driver = {
.probe = serial_pxa_probe,
- .remove_new = serial_pxa_remove,
+ .remove = serial_pxa_remove,
.driver = {
.name = "pxa2xx-uart",
@@ -164,22 +165,7 @@ static struct platform_driver serial_pxa_driver = {
module_platform_driver(serial_pxa_driver);
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-static int __init early_serial_pxa_setup(struct earlycon_device *device,
- const char *options)
-{
- struct uart_port *port = &device->port;
-
- if (!(device->port.membase || device->port.iobase))
- return -ENODEV;
-
- port->regshift = 2;
- return early_serial8250_setup(device, NULL);
-}
-OF_EARLYCON_DECLARE(early_pxa, "mrvl,pxa-uart", early_serial_pxa_setup);
-OF_EARLYCON_DECLARE(mmp, "mrvl,mmp-uart", early_serial_pxa_setup);
-#endif
-
MODULE_AUTHOR("Sergei Ianovich");
+MODULE_DESCRIPTION("driver for PXA on-board UARTS");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pxa2xx-uart");
diff --git a/drivers/tty/serial/8250/8250_rsa.c b/drivers/tty/serial/8250/8250_rsa.c
new file mode 100644
index 000000000000..82f2593b4c59
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_rsa.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <linux/serial.h>
+#include <linux/serial_8250.h>
+
+#include "8250.h"
+
+#define PORT_RSA_MAX 4
+static unsigned long probe_rsa[PORT_RSA_MAX];
+static unsigned int probe_rsa_count;
+
+static int rsa8250_request_resource(struct uart_8250_port *up)
+{
+ struct uart_port *port = &up->port;
+ unsigned long start = UART_RSA_BASE << port->regshift;
+ unsigned int size = 8 << port->regshift;
+
+ switch (port->iotype) {
+ case UPIO_HUB6:
+ case UPIO_PORT:
+ start += port->iobase;
+ if (!request_region(start, size, "serial-rsa"))
+ return -EBUSY;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void rsa8250_release_resource(struct uart_8250_port *up)
+{
+ struct uart_port *port = &up->port;
+ unsigned long offset = UART_RSA_BASE << port->regshift;
+ unsigned int size = 8 << port->regshift;
+
+ switch (port->iotype) {
+ case UPIO_HUB6:
+ case UPIO_PORT:
+ release_region(port->iobase + offset, size);
+ break;
+ }
+}
+
+static void univ8250_config_port(struct uart_port *port, int flags)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned int i;
+
+ up->probe &= ~UART_PROBE_RSA;
+ if (port->type == PORT_RSA) {
+ if (rsa8250_request_resource(up) == 0)
+ up->probe |= UART_PROBE_RSA;
+ } else if (flags & UART_CONFIG_TYPE) {
+ for (i = 0; i < probe_rsa_count; i++) {
+ if (probe_rsa[i] == up->port.iobase) {
+ if (rsa8250_request_resource(up) == 0)
+ up->probe |= UART_PROBE_RSA;
+ break;
+ }
+ }
+ }
+
+ univ8250_port_base_ops->config_port(port, flags);
+
+ if (port->type != PORT_RSA && up->probe & UART_PROBE_RSA)
+ rsa8250_release_resource(up);
+}
+
+static int univ8250_request_port(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ int ret;
+
+ ret = univ8250_port_base_ops->request_port(port);
+ if (ret == 0 && port->type == PORT_RSA) {
+ ret = rsa8250_request_resource(up);
+ if (ret < 0)
+ univ8250_port_base_ops->release_port(port);
+ }
+
+ return ret;
+}
+
+static void univ8250_release_port(struct uart_port *port)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ if (port->type == PORT_RSA)
+ rsa8250_release_resource(up);
+ univ8250_port_base_ops->release_port(port);
+}
+
+void univ8250_rsa_support(struct uart_ops *ops)
+{
+ ops->config_port = univ8250_config_port;
+ ops->request_port = univ8250_request_port;
+ ops->release_port = univ8250_release_port;
+}
+
+module_param_hw_array(probe_rsa, ulong, ioport, &probe_rsa_count, 0444);
+MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
+
+#ifdef CONFIG_SERIAL_8250_DEPRECATED_OPTIONS
+#ifndef MODULE
+/*
+ * Keep the old "8250" name working as well for the module options so we don't
+ * break people. We need to keep the names identical and the convenient macros
+ * will happily refuse to let us do that by failing the build with redefinition
+ * errors of global variables. So we stick them inside a dummy function to
+ * avoid those conflicts. The options still get parsed, and the redefined
+ * MODULE_PARAM_PREFIX lets us keep the "8250." syntax alive.
+ *
+ * This is hacky. I'm sorry.
+ */
+static void __used rsa8250_options(void)
+{
+#undef MODULE_PARAM_PREFIX
+#define MODULE_PARAM_PREFIX "8250_core."
+
+ __module_param_call(MODULE_PARAM_PREFIX, probe_rsa,
+ &param_array_ops, .arr = &__param_arr_probe_rsa,
+ 0444, -1, 0);
+}
+#endif
+#endif
diff --git a/drivers/tty/serial/8250/8250_tegra.c b/drivers/tty/serial/8250/8250_tegra.c
index 60a80d00d251..2f3b0075763f 100644
--- a/drivers/tty/serial/8250/8250_tegra.c
+++ b/drivers/tty/serial/8250/8250_tegra.c
@@ -182,7 +182,7 @@ static struct platform_driver tegra_uart_driver = {
.acpi_match_table = ACPI_PTR(tegra_uart_acpi_match),
},
.probe = tegra_uart_probe,
- .remove_new = tegra_uart_remove,
+ .remove = tegra_uart_remove,
};
module_platform_driver(tegra_uart_driver);
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index 670d2ca0f757..4874a9632db3 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -282,7 +282,7 @@ MODULE_DEVICE_TABLE(of, uniphier_uart_match);
static struct platform_driver uniphier_uart_platform_driver = {
.probe = uniphier_uart_probe,
- .remove_new = uniphier_uart_remove,
+ .remove = uniphier_uart_remove,
.driver = {
.name = "uniphier-uart",
.of_match_table = uniphier_uart_match,
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 47ff50763c04..bd3d636ff962 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -72,7 +72,7 @@ config SERIAL_8250_16550A_VARIANTS
config SERIAL_8250_FINTEK
bool "Support for Fintek variants"
- depends on SERIAL_8250
+ depends on SERIAL_8250 && HAS_IOPORT
help
Selecting this option will add support for the RS232 and RS485
capabilities of the Fintek F81216A LPC to 4 UART as well similar
@@ -150,6 +150,7 @@ config SERIAL_8250_EXAR
tristate "8250/16550 Exar/Commtech PCI/PCIe device support"
depends on SERIAL_8250 && PCI
select SERIAL_8250_PCILIB
+ select EEPROM_93CX6
default SERIAL_8250
help
This builds support for XR17C1xx, XR17V3xx and some Commtech
@@ -163,7 +164,7 @@ config SERIAL_8250_HP300
config SERIAL_8250_CS
tristate "8250/16550 PCMCIA device support"
- depends on PCMCIA && SERIAL_8250
+ depends on PCMCIA && SERIAL_8250 && HAS_IOPORT
help
Say Y here to enable support for 16-bit PCMCIA serial devices,
including serial port cards, modems, and the modem functions of
@@ -568,6 +569,19 @@ config SERIAL_8250_BCM7271
including DMA support and high accuracy BAUD rates, say
Y to this option. If unsure, say N.
+config SERIAL_8250_NI
+ tristate "NI 16550 based serial port"
+ depends on SERIAL_8250
+ depends on (X86 && ACPI) || COMPILE_TEST
+ help
+ This driver supports the integrated serial ports on National
+ Instruments (NI) controller hardware. This is required for all NI
+ controller models with onboard RS-485 or dual-mode RS-485/RS-232
+ ports.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_ni.
+
config SERIAL_OF_PLATFORM
tristate "Devicetree based probing for 8250 ports"
depends on SERIAL_8250 && OF
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index ea2e81f58eac..b04eeda03b23 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -3,11 +3,13 @@
# Makefile for the 8250 serial device drivers.
#
-obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o
+obj-$(CONFIG_SERIAL_8250) += 8250.o
8250-y := 8250_core.o
-8250-$(CONFIG_ALPHA_GENERIC) += 8250_alpha.o
-8250-$(CONFIG_ALPHA_JENSEN) += 8250_alpha.o
+8250-y += 8250_platform.o
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
+8250-$(CONFIG_SERIAL_8250_RSA) += 8250_rsa.o
+
+obj-$(CONFIG_SERIAL_8250) += 8250_base.o
8250_base-y := 8250_port.o
8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
8250_base-$(CONFIG_SERIAL_8250_DWLIB) += 8250_dwlib.o
@@ -38,6 +40,7 @@ obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o
obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o
obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
+obj-$(CONFIG_SERIAL_8250_NI) += 8250_ni.o
obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
obj-$(CONFIG_SERIAL_8250_PARISC) += 8250_parisc.o
diff --git a/drivers/tty/serial/8250/serial_cs.c b/drivers/tty/serial/8250/serial_cs.c
index 2056aed46688..58e279ea7ee0 100644
--- a/drivers/tty/serial/8250/serial_cs.c
+++ b/drivers/tty/serial/8250/serial_cs.c
@@ -864,4 +864,5 @@ static struct pcmcia_driver serial_cs_driver = {
};
module_pcmcia_driver(serial_cs_driver);
+MODULE_DESCRIPTION("driver for PCMCIA serial devices");
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index ffcf4882b25f..79a8186d3361 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -128,7 +128,7 @@ config SERIAL_SB1250_DUART_CONSOLE
config SERIAL_ATMEL
bool "AT91 on-chip serial port support"
depends on COMMON_CLK
- depends on ARCH_AT91 || COMPILE_TEST
+ depends on ARCH_AT91 || ARCH_LAN969X || COMPILE_TEST
select SERIAL_CORE
select SERIAL_MCTRL_GPIO if GPIOLIB
select MFD_AT91_USART
@@ -179,25 +179,6 @@ config SERIAL_ATMEL_TTYAT
Say Y if you have an external 8250/16C550 UART. If unsure, say N.
-config SERIAL_KGDB_NMI
- bool "Serial console over KGDB NMI debugger port"
- depends on KGDB_SERIAL_CONSOLE
- help
- This special driver allows you to temporary use NMI debugger port
- as a normal console (assuming that the port is attached to KGDB).
-
- Unlike KDB's disable_nmi command, with this driver you are always
- able to go back to the debugger using KGDB escape sequence ($3#33).
- This is because this console driver processes the input in NMI
- context, and thus is able to intercept the magic sequence.
-
- Note that since the console interprets input and uses polling
- communication methods, for things like PPP you still must fully
- detach debugger port from the KGDB NMI (i.e. disable_nmi), and
- use raw console.
-
- If unsure, say N.
-
config SERIAL_MESON
tristate "Meson serial port support"
depends on ARCH_MESON || COMPILE_TEST
@@ -306,12 +287,38 @@ config SERIAL_TEGRA_TCU_CONSOLE
If unsure, say Y.
+config SERIAL_TEGRA_UTC
+ tristate "NVIDIA Tegra UART Trace Controller"
+ depends on ARCH_TEGRA || COMPILE_TEST
+ select SERIAL_CORE
+ help
+ Support for Tegra UTC (UART Trace controller) client serial port.
+
+ UTC is a HW based serial port that allows multiplexing multiple data
+ streams of up to 16 UTC clients into a single hardware serial port.
+
+config SERIAL_TEGRA_UTC_CONSOLE
+ bool "Support for console on a Tegra UTC serial port"
+ depends on SERIAL_TEGRA_UTC
+ select SERIAL_CORE_CONSOLE
+ default SERIAL_TEGRA_UTC
+ help
+ If you say Y here, it will be possible to use a Tegra UTC client as
+ the system console (the system console is the device which receives
+ all kernel messages and warnings and which allows logins in single
+ user mode).
+
+ If unsure, say Y.
+
config SERIAL_MAX3100
- tristate "MAX3100 support"
+ tristate "MAX3100/3110/3111/3222 support"
depends on SPI
select SERIAL_CORE
help
- MAX3100 chip support
+ This selects support for an advanced UART from Maxim.
+ Supported ICs are MAX3100, MAX3110, MAX3111, MAX3222.
+
+ Say Y here if you want to support these ICs.
config SERIAL_MAX310X
tristate "MAX310X support"
@@ -874,7 +881,7 @@ config SERIAL_TXX9_STDSERIAL
config SERIAL_JSM
tristate "Digi International NEO and Classic PCI Support"
- depends on PCI
+ depends on PCI && HAS_IOPORT
select SERIAL_CORE
help
This is a driver for Digi International's Neo and Classic series
@@ -1020,42 +1027,32 @@ config SERIAL_SCCNXP_CONSOLE
help
Support for console on SCCNXP serial ports.
-config SERIAL_SC16IS7XX_CORE
- tristate
-
config SERIAL_SC16IS7XX
- tristate "SC16IS7xx serial support"
+ tristate "NXP SC16IS7xx UART support"
+ depends on SPI_MASTER || I2C
select SERIAL_CORE
- depends on (SPI_MASTER && !I2C) || I2C
+ select SERIAL_SC16IS7XX_SPI if SPI_MASTER
+ select SERIAL_SC16IS7XX_I2C if I2C
help
- This selects support for SC16IS7xx serial ports.
- Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752,
- SC16IS760 and SC16IS762. Select supported buses using options below.
+ Core driver for NXP SC16IS7xx UARTs.
+ Supported ICs are:
+
+ SC16IS740
+ SC16IS741
+ SC16IS750
+ SC16IS752
+ SC16IS760
+ SC16IS762
+
+ The driver supports both I2C and SPI interfaces.
config SERIAL_SC16IS7XX_I2C
- bool "SC16IS7xx for I2C interface"
- depends on SERIAL_SC16IS7XX
- depends on I2C
- select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
- select REGMAP_I2C if I2C
- default y
- help
- Enable SC16IS7xx driver on I2C bus,
- If required say y, and say n to i2c if not required,
- Enabled by default to support oldconfig.
- You must select at least one bus for the driver to be built.
+ tristate
+ select REGMAP_I2C
config SERIAL_SC16IS7XX_SPI
- bool "SC16IS7xx for spi interface"
- depends on SERIAL_SC16IS7XX
- depends on SPI_MASTER
- select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX
- select REGMAP_SPI if SPI_MASTER
- help
- Enable SC16IS7xx driver on SPI bus,
- If required say y, and say n to spi if not required,
- This is additional support to existing driver.
- You must select at least one bus for the driver to be built.
+ tristate
+ select REGMAP_SPI
config SERIAL_TIMBERDALE
tristate "Support for timberdale UART"
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index b25e9b54a660..d58d9f719889 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -75,7 +75,9 @@ obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
obj-$(CONFIG_SERIAL_SAMSUNG) += samsung_tty.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
-obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o
+obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
+obj-$(CONFIG_SERIAL_SC16IS7XX_SPI) += sc16is7xx_spi.o
+obj-$(CONFIG_SERIAL_SC16IS7XX_I2C) += sc16is7xx_i2c.o
obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
obj-$(CONFIG_SERIAL_SIFIVE) += sifive.o
obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
@@ -84,6 +86,7 @@ obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o
obj-$(CONFIG_SERIAL_SUNPLUS) += sunplus-uart.o
obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o
obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o
+obj-$(CONFIG_SERIAL_TEGRA_UTC) += tegra-utc.o
obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
@@ -94,6 +97,5 @@ obj-$(CONFIG_SERIAL_ZS) += zs.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
-obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o
obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o
obj-$(CONFIG_SERIAL_NUVOTON_MA35D1) += ma35d1_serial.o
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index effcba71ea77..d47a62d1c9f7 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -24,8 +24,6 @@
#include <linux/io.h>
#include <linux/altera_jtaguart.h>
-#define DRV_NAME "altera_jtaguart"
-
/*
* Altera JTAG UART register definitions according to the Altera JTAG UART
* datasheet: https://www.altera.com/literature/hb/nios2/n2cpu_nii51009.pdf
@@ -173,10 +171,10 @@ static int altera_jtaguart_startup(struct uart_port *port)
int ret;
ret = request_irq(port->irq, altera_jtaguart_interrupt, 0,
- DRV_NAME, port);
+ dev_name(port->dev), port);
if (ret) {
- pr_err(DRV_NAME ": unable to attach Altera JTAG UART %d "
- "interrupt vector=%d\n", port->line, port->irq);
+ dev_err(port->dev, "unable to attach Altera JTAG UART %d interrupt vector=%d\n",
+ port->line, port->irq);
return ret;
}
@@ -365,7 +363,7 @@ OF_EARLYCON_DECLARE(juart, "altr,juart-1.0", altera_jtaguart_earlycon_setup);
static struct uart_driver altera_jtaguart_driver = {
.owner = THIS_MODULE,
- .driver_name = "altera_jtaguart",
+ .driver_name = KBUILD_MODNAME,
.dev_name = "ttyJ",
.major = ALTERA_JTAGUART_MAJOR,
.minor = ALTERA_JTAGUART_MINOR,
@@ -449,9 +447,9 @@ MODULE_DEVICE_TABLE(of, altera_jtaguart_match);
static struct platform_driver altera_jtaguart_platform_driver = {
.probe = altera_jtaguart_probe,
- .remove_new = altera_jtaguart_remove,
+ .remove = altera_jtaguart_remove,
.driver = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.of_match_table = of_match_ptr(altera_jtaguart_match),
},
};
@@ -481,4 +479,4 @@ module_exit(altera_jtaguart_exit);
MODULE_DESCRIPTION("Altera JTAG UART driver");
MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index 897f0995b2fe..011f38681131 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -24,7 +24,6 @@
#include <linux/io.h>
#include <linux/altera_uart.h>
-#define DRV_NAME "altera_uart"
#define SERIAL_ALTERA_MAJOR 204
#define SERIAL_ALTERA_MINOR 213
@@ -307,8 +306,8 @@ static int altera_uart_startup(struct uart_port *port)
ret = request_irq(port->irq, altera_uart_interrupt, 0,
dev_name(port->dev), port);
if (ret) {
- pr_err(DRV_NAME ": unable to attach Altera UART %d "
- "interrupt vector=%d\n", port->line, port->irq);
+ dev_err(port->dev, "unable to attach Altera UART %d interrupt vector=%d\n",
+ port->line, port->irq);
return ret;
}
}
@@ -340,7 +339,7 @@ static void altera_uart_shutdown(struct uart_port *port)
if (port->irq)
free_irq(port->irq, port);
else
- del_timer_sync(&pp->tmr);
+ timer_delete_sync(&pp->tmr);
}
static const char *altera_uart_type(struct uart_port *port)
@@ -518,7 +517,7 @@ OF_EARLYCON_DECLARE(uart, "altr,uart-1.0", altera_uart_earlycon_setup);
*/
static struct uart_driver altera_uart_driver = {
.owner = THIS_MODULE,
- .driver_name = DRV_NAME,
+ .driver_name = KBUILD_MODNAME,
.dev_name = "ttyAL",
.major = SERIAL_ALTERA_MAJOR,
.minor = SERIAL_ALTERA_MINOR,
@@ -617,9 +616,9 @@ MODULE_DEVICE_TABLE(of, altera_uart_match);
static struct platform_driver altera_uart_platform_driver = {
.probe = altera_uart_probe,
- .remove_new = altera_uart_remove,
+ .remove = altera_uart_remove,
.driver = {
- .name = DRV_NAME,
+ .name = KBUILD_MODNAME,
.of_match_table = of_match_ptr(altera_uart_match),
},
};
@@ -649,5 +648,5 @@ module_exit(altera_uart_exit);
MODULE_DESCRIPTION("Altera UART driver");
MODULE_AUTHOR("Thomas Chou <thomas@wytron.com.tw>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
MODULE_ALIAS_CHARDEV_MAJOR(SERIAL_ALTERA_MAJOR);
diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c
index eabbf8afc9b5..c3a7fad02ac9 100644
--- a/drivers/tty/serial/amba-pl010.c
+++ b/drivers/tty/serial/amba-pl010.c
@@ -499,7 +499,7 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
int ret = 0;
if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
ret = -EINVAL;
- if (ser->irq < 0 || ser->irq >= nr_irqs)
+ if (ser->irq < 0 || ser->irq >= irq_get_nr_irqs())
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index 2fa3fb30dc6c..11d65097578c 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -248,6 +248,13 @@ struct pl011_dmatx_data {
bool queued;
};
+enum pl011_rs485_tx_state {
+ OFF,
+ WAIT_AFTER_RTS,
+ SEND,
+ WAIT_AFTER_SEND,
+};
+
/*
* We wrap our port structure around the generic uart_port.
*/
@@ -256,16 +263,19 @@ struct uart_amba_port {
const u16 *reg_offset;
struct clk *clk;
const struct vendor_data *vendor;
- unsigned int dmacr; /* dma control reg */
unsigned int im; /* interrupt mask */
unsigned int old_status;
unsigned int fifosize; /* vendor-specific */
unsigned int fixed_baud; /* vendor-set fixed baud rate */
char type[12];
- bool rs485_tx_started;
- unsigned int rs485_tx_drain_interval; /* usecs */
+ ktime_t rs485_tx_drain_interval; /* nano */
+ enum pl011_rs485_tx_state rs485_tx_state;
+ struct hrtimer trigger_start_tx;
+ struct hrtimer trigger_stop_tx;
+ bool console_line_ended;
#ifdef CONFIG_DMA_ENGINE
/* DMA stuff */
+ unsigned int dmacr; /* dma control reg */
bool using_tx_dma;
bool using_rx_dma;
struct pl011_dmarx_data dmarx;
@@ -535,6 +545,7 @@ static void pl011_start_tx_pio(struct uart_amba_port *uap);
static void pl011_dma_tx_callback(void *data)
{
struct uart_amba_port *uap = data;
+ struct tty_port *tport = &uap->port.state->port;
struct pl011_dmatx_data *dmatx = &uap->dmatx;
unsigned long flags;
u16 dmacr;
@@ -558,7 +569,7 @@ static void pl011_dma_tx_callback(void *data)
* get further refills (hence we check dmacr).
*/
if (!(dmacr & UART011_TXDMAE) || uart_tx_stopped(&uap->port) ||
- uart_circ_empty(&uap->port.state->xmit)) {
+ kfifo_is_empty(&tport->xmit_fifo)) {
uap->dmatx.queued = false;
uart_port_unlock_irqrestore(&uap->port, flags);
return;
@@ -588,7 +599,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
struct dma_chan *chan = dmatx->chan;
struct dma_device *dma_dev = chan->device;
struct dma_async_tx_descriptor *desc;
- struct circ_buf *xmit = &uap->port.state->xmit;
+ struct tty_port *tport = &uap->port.state->port;
unsigned int count;
/*
@@ -597,7 +608,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
* the standard interrupt handling. This ensures that we
* issue a uart_write_wakeup() at the appropriate time.
*/
- count = uart_circ_chars_pending(xmit);
+ count = kfifo_len(&tport->xmit_fifo);
if (count < (uap->fifosize >> 1)) {
uap->dmatx.queued = false;
return 0;
@@ -613,21 +624,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
if (count > PL011_DMA_BUFFER_SIZE)
count = PL011_DMA_BUFFER_SIZE;
- if (xmit->tail < xmit->head) {
- memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], count);
- } else {
- size_t first = UART_XMIT_SIZE - xmit->tail;
- size_t second;
-
- if (first > count)
- first = count;
- second = count - first;
-
- memcpy(&dmatx->buf[0], &xmit->buf[xmit->tail], first);
- if (second)
- memcpy(&dmatx->buf[first], &xmit->buf[0], second);
- }
-
+ count = kfifo_out_peek(&tport->xmit_fifo, dmatx->buf, count);
dmatx->len = count;
dmatx->dma = dma_map_single(dma_dev->dev, dmatx->buf, count,
DMA_TO_DEVICE);
@@ -670,7 +667,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap)
*/
uart_xmit_advance(&uap->port, count);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
return 1;
@@ -1087,7 +1084,7 @@ static void pl011_dma_rx_poll(struct timer_list *t)
uap->dmarx.running = false;
dmaengine_terminate_all(rxchan);
- del_timer(&uap->dmarx.timer);
+ timer_delete(&uap->dmarx.timer);
} else {
mod_timer(&uap->dmarx.timer,
jiffies + msecs_to_jiffies(uap->dmarx.poll_rate));
@@ -1202,7 +1199,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE);
pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE);
if (uap->dmarx.poll_rate)
- del_timer_sync(&uap->dmarx.timer);
+ timer_delete_sync(&uap->dmarx.timer);
uap->using_rx_dma = false;
}
}
@@ -1273,30 +1270,31 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
{
- /*
- * To be on the safe side only time out after twice as many iterations
- * as fifo size.
- */
- const int MAX_TX_DRAIN_ITERS = uap->port.fifosize * 2;
struct uart_port *port = &uap->port;
- int i = 0;
u32 cr;
- /* Wait until hardware tx queue is empty */
- while (!pl011_tx_empty(port)) {
- if (i > MAX_TX_DRAIN_ITERS) {
- dev_warn(port->dev,
- "timeout while draining hardware tx queue\n");
- break;
- }
+ if (uap->rs485_tx_state == SEND)
+ uap->rs485_tx_state = WAIT_AFTER_SEND;
- udelay(uap->rs485_tx_drain_interval);
- i++;
+ if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
+ /* Schedule hrtimer if tx queue not empty */
+ if (!pl011_tx_empty(port)) {
+ hrtimer_start(&uap->trigger_stop_tx,
+ uap->rs485_tx_drain_interval,
+ HRTIMER_MODE_REL);
+ return;
+ }
+ if (port->rs485.delay_rts_after_send > 0) {
+ hrtimer_start(&uap->trigger_stop_tx,
+ ms_to_ktime(port->rs485.delay_rts_after_send),
+ HRTIMER_MODE_REL);
+ return;
+ }
+ /* Continue without any delay */
+ } else if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
+ hrtimer_try_to_cancel(&uap->trigger_start_tx);
}
- if (port->rs485.delay_rts_after_send)
- mdelay(port->rs485.delay_rts_after_send);
-
cr = pl011_read(uap, REG_CR);
if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
@@ -1309,7 +1307,7 @@ static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
cr |= UART011_CR_RXE;
pl011_write(cr, uap, REG_CR);
- uap->rs485_tx_started = false;
+ uap->rs485_tx_state = OFF;
}
static void pl011_stop_tx(struct uart_port *port)
@@ -1317,11 +1315,18 @@ static void pl011_stop_tx(struct uart_port *port)
struct uart_amba_port *uap =
container_of(port, struct uart_amba_port, port);
+ if (port->rs485.flags & SER_RS485_ENABLED &&
+ uap->rs485_tx_state == WAIT_AFTER_RTS) {
+ pl011_rs485_tx_stop(uap);
+ return;
+ }
+
uap->im &= ~UART011_TXIM;
pl011_write(uap->im, uap, REG_IMSC);
pl011_dma_tx_stop(uap);
- if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
+ if (port->rs485.flags & SER_RS485_ENABLED &&
+ uap->rs485_tx_state != OFF)
pl011_rs485_tx_stop(uap);
}
@@ -1341,10 +1346,19 @@ static void pl011_rs485_tx_start(struct uart_amba_port *uap)
struct uart_port *port = &uap->port;
u32 cr;
+ if (uap->rs485_tx_state == WAIT_AFTER_RTS) {
+ uap->rs485_tx_state = SEND;
+ return;
+ }
+ if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
+ hrtimer_try_to_cancel(&uap->trigger_stop_tx);
+ uap->rs485_tx_state = SEND;
+ return;
+ }
+ /* uap->rs485_tx_state == OFF */
/* Enable transmitter */
cr = pl011_read(uap, REG_CR);
cr |= UART011_CR_TXE;
-
/* Disable receiver if half-duplex */
if (!(port->rs485.flags & SER_RS485_RX_DURING_TX))
cr &= ~UART011_CR_RXE;
@@ -1356,10 +1370,14 @@ static void pl011_rs485_tx_start(struct uart_amba_port *uap)
pl011_write(cr, uap, REG_CR);
- if (port->rs485.delay_rts_before_send)
- mdelay(port->rs485.delay_rts_before_send);
-
- uap->rs485_tx_started = true;
+ if (port->rs485.delay_rts_before_send > 0) {
+ uap->rs485_tx_state = WAIT_AFTER_RTS;
+ hrtimer_start(&uap->trigger_start_tx,
+ ms_to_ktime(port->rs485.delay_rts_before_send),
+ HRTIMER_MODE_REL);
+ } else {
+ uap->rs485_tx_state = SEND;
+ }
}
static void pl011_start_tx(struct uart_port *port)
@@ -1368,13 +1386,44 @@ static void pl011_start_tx(struct uart_port *port)
container_of(port, struct uart_amba_port, port);
if ((uap->port.rs485.flags & SER_RS485_ENABLED) &&
- !uap->rs485_tx_started)
+ uap->rs485_tx_state != SEND) {
pl011_rs485_tx_start(uap);
+ if (uap->rs485_tx_state == WAIT_AFTER_RTS)
+ return;
+ }
if (!pl011_dma_tx_start(uap))
pl011_start_tx_pio(uap);
}
+static enum hrtimer_restart pl011_trigger_start_tx(struct hrtimer *t)
+{
+ struct uart_amba_port *uap =
+ container_of(t, struct uart_amba_port, trigger_start_tx);
+ unsigned long flags;
+
+ uart_port_lock_irqsave(&uap->port, &flags);
+ if (uap->rs485_tx_state == WAIT_AFTER_RTS)
+ pl011_start_tx(&uap->port);
+ uart_port_unlock_irqrestore(&uap->port, flags);
+
+ return HRTIMER_NORESTART;
+}
+
+static enum hrtimer_restart pl011_trigger_stop_tx(struct hrtimer *t)
+{
+ struct uart_amba_port *uap =
+ container_of(t, struct uart_amba_port, trigger_stop_tx);
+ unsigned long flags;
+
+ uart_port_lock_irqsave(&uap->port, &flags);
+ if (uap->rs485_tx_state == WAIT_AFTER_SEND)
+ pl011_rs485_tx_stop(uap);
+ uart_port_unlock_irqrestore(&uap->port, flags);
+
+ return HRTIMER_NORESTART;
+}
+
static void pl011_stop_rx(struct uart_port *port)
{
struct uart_amba_port *uap =
@@ -1454,7 +1503,7 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c,
/* Returns true if tx interrupts have to be (kept) enabled */
static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
{
- struct circ_buf *xmit = &uap->port.state->xmit;
+ struct tty_port *tport = &uap->port.state->port;
int count = uap->fifosize >> 1;
if (uap->port.x_char) {
@@ -1463,7 +1512,7 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
uap->port.x_char = 0;
--count;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(&uap->port)) {
pl011_stop_tx(&uap->port);
return false;
}
@@ -1472,20 +1521,25 @@ static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq)
if (pl011_dma_tx_irq(uap))
return true;
- do {
+ while (1) {
+ unsigned char c;
+
if (likely(from_irq) && count-- == 0)
break;
- if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq))
+ if (!kfifo_peek(&tport->xmit_fifo, &c))
break;
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- } while (!uart_circ_empty(xmit));
+ if (!pl011_tx_char(uap, c, from_irq))
+ break;
+
+ kfifo_skip(&tport->xmit_fifo);
+ }
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
- if (uart_circ_empty(xmit)) {
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
pl011_stop_tx(&uap->port);
return false;
}
@@ -1827,6 +1881,13 @@ static void pl011_unthrottle_rx(struct uart_port *port)
pl011_write(uap->im, uap, REG_IMSC);
+#ifdef CONFIG_DMA_ENGINE
+ if (uap->using_rx_dma) {
+ uap->dmacr |= UART011_RXDMAE;
+ pl011_write(uap->dmacr, uap, REG_DMACR);
+ }
+#endif
+
uart_port_unlock_irqrestore(&uap->port, flags);
}
@@ -1954,7 +2015,7 @@ static void pl011_shutdown(struct uart_port *port)
pl011_dma_shutdown(uap);
- if ((port->rs485.flags & SER_RS485_ENABLED) && uap->rs485_tx_started)
+ if ((port->rs485.flags & SER_RS485_ENABLED && uap->rs485_tx_state != OFF))
pl011_rs485_tx_stop(uap);
free_irq(uap->port.irq, uap);
@@ -2099,7 +2160,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios,
* with the given baud rate. We use this as the poll interval when we
* wait for the tx queue to empty.
*/
- uap->rs485_tx_drain_interval = DIV_ROUND_UP(bits * 1000 * 1000, baud);
+ uap->rs485_tx_drain_interval = ns_to_ktime(DIV_ROUND_UP(bits * NSEC_PER_SEC, baud));
pl011_setup_status_masks(port, termios);
@@ -2210,7 +2271,7 @@ static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
ret = -EINVAL;
- if (ser->irq < 0 || ser->irq >= nr_irqs)
+ if (ser->irq < 0 || ser->irq >= irq_get_nr_irqs())
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
@@ -2306,50 +2367,7 @@ static void pl011_console_putchar(struct uart_port *port, unsigned char ch)
while (pl011_read(uap, REG_FR) & UART01x_FR_TXFF)
cpu_relax();
pl011_write(ch, uap, REG_DR);
-}
-
-static void
-pl011_console_write(struct console *co, const char *s, unsigned int count)
-{
- struct uart_amba_port *uap = amba_ports[co->index];
- unsigned int old_cr = 0, new_cr;
- unsigned long flags;
- int locked = 1;
-
- clk_enable(uap->clk);
-
- if (oops_in_progress)
- locked = uart_port_trylock_irqsave(&uap->port, &flags);
- else
- uart_port_lock_irqsave(&uap->port, &flags);
-
- /*
- * First save the CR then disable the interrupts
- */
- if (!uap->vendor->always_enabled) {
- old_cr = pl011_read(uap, REG_CR);
- new_cr = old_cr & ~UART011_CR_CTSEN;
- new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE;
- pl011_write(new_cr, uap, REG_CR);
- }
-
- uart_console_write(&uap->port, s, count, pl011_console_putchar);
-
- /*
- * Finally, wait for transmitter to become empty and restore the
- * TCR. Allow feature register bits to be inverted to work around
- * errata.
- */
- while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr)
- & uap->vendor->fr_busy)
- cpu_relax();
- if (!uap->vendor->always_enabled)
- pl011_write(old_cr, uap, REG_CR);
-
- if (locked)
- uart_port_unlock_irqrestore(&uap->port, flags);
-
- clk_disable(uap->clk);
+ uap->console_line_ended = (ch == '\n');
}
static void pl011_console_get_options(struct uart_amba_port *uap, int *baud,
@@ -2412,6 +2430,8 @@ static int pl011_console_setup(struct console *co, char *options)
if (ret)
return ret;
+ uap->console_line_ended = true;
+
if (dev_get_platdata(uap->port.dev)) {
struct amba_pl011_data *plat;
@@ -2488,21 +2508,112 @@ static int pl011_console_match(struct console *co, char *name, int idx,
continue;
co->index = i;
- port->cons = co;
+ uart_port_set_cons(port, co);
return pl011_console_setup(co, options);
}
return -ENODEV;
}
+static void
+pl011_console_write_atomic(struct console *co, struct nbcon_write_context *wctxt)
+{
+ struct uart_amba_port *uap = amba_ports[co->index];
+ unsigned int old_cr = 0;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ clk_enable(uap->clk);
+
+ if (!uap->vendor->always_enabled) {
+ old_cr = pl011_read(uap, REG_CR);
+ pl011_write((old_cr & ~UART011_CR_CTSEN) | (UART01x_CR_UARTEN | UART011_CR_TXE),
+ uap, REG_CR);
+ }
+
+ if (!uap->console_line_ended)
+ uart_console_write(&uap->port, "\n", 1, pl011_console_putchar);
+ uart_console_write(&uap->port, wctxt->outbuf, wctxt->len, pl011_console_putchar);
+
+ while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy)
+ cpu_relax();
+
+ if (!uap->vendor->always_enabled)
+ pl011_write(old_cr, uap, REG_CR);
+
+ clk_disable(uap->clk);
+
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void
+pl011_console_write_thread(struct console *co, struct nbcon_write_context *wctxt)
+{
+ struct uart_amba_port *uap = amba_ports[co->index];
+ unsigned int old_cr = 0;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ clk_enable(uap->clk);
+
+ if (!uap->vendor->always_enabled) {
+ old_cr = pl011_read(uap, REG_CR);
+ pl011_write((old_cr & ~UART011_CR_CTSEN) | (UART01x_CR_UARTEN | UART011_CR_TXE),
+ uap, REG_CR);
+ }
+
+ if (nbcon_exit_unsafe(wctxt)) {
+ int i;
+ unsigned int len = READ_ONCE(wctxt->len);
+
+ for (i = 0; i < len; i++) {
+ if (!nbcon_enter_unsafe(wctxt))
+ break;
+ uart_console_write(&uap->port, wctxt->outbuf + i, 1, pl011_console_putchar);
+ if (!nbcon_exit_unsafe(wctxt))
+ break;
+ }
+ }
+
+ while (!nbcon_enter_unsafe(wctxt))
+ nbcon_reacquire_nobuf(wctxt);
+
+ while ((pl011_read(uap, REG_FR) ^ uap->vendor->inv_fr) & uap->vendor->fr_busy)
+ cpu_relax();
+
+ if (!uap->vendor->always_enabled)
+ pl011_write(old_cr, uap, REG_CR);
+
+ clk_disable(uap->clk);
+
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void
+pl011_console_device_lock(struct console *co, unsigned long *flags)
+{
+ __uart_port_lock_irqsave(&amba_ports[co->index]->port, flags);
+}
+
+static void
+pl011_console_device_unlock(struct console *co, unsigned long flags)
+{
+ __uart_port_unlock_irqrestore(&amba_ports[co->index]->port, flags);
+}
+
static struct uart_driver amba_reg;
static struct console amba_console = {
.name = "ttyAMA",
- .write = pl011_console_write,
.device = uart_console_device,
.setup = pl011_console_setup,
.match = pl011_console_match,
- .flags = CON_PRINTBUFFER | CON_ANYTIME,
+ .write_atomic = pl011_console_write_atomic,
+ .write_thread = pl011_console_write_thread,
+ .device_lock = pl011_console_device_lock,
+ .device_unlock = pl011_console_device_unlock,
+ .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_NBCON,
.index = -1,
.data = &amba_reg,
};
@@ -2700,18 +2811,6 @@ static int pl011_find_free_port(void)
return -EBUSY;
}
-static int pl011_get_rs485_mode(struct uart_amba_port *uap)
-{
- struct uart_port *port = &uap->port;
- int ret;
-
- ret = uart_get_rs485_mode(port);
- if (ret)
- return ret;
-
- return 0;
-}
-
static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
struct resource *mmiobase, int index)
{
@@ -2732,7 +2831,7 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap,
uap->port.flags = UPF_BOOT_AUTOCONF;
uap->port.line = index;
- ret = pl011_get_rs485_mode(uap);
+ ret = uart_get_rs485_mode(&uap->port);
if (ret)
return ret;
@@ -2819,6 +2918,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
return -EINVAL;
}
}
+ hrtimer_setup(&uap->trigger_start_tx, pl011_trigger_start_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ hrtimer_setup(&uap->trigger_stop_tx, pl011_trigger_stop_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr);
if (ret)
@@ -2948,7 +3051,7 @@ static const struct of_device_id sbsa_uart_of_match[] = {
};
MODULE_DEVICE_TABLE(of, sbsa_uart_of_match);
-static const struct acpi_device_id __maybe_unused sbsa_uart_acpi_match[] = {
+static const struct acpi_device_id sbsa_uart_acpi_match[] = {
{ "ARMH0011", 0 },
{ "ARMHB000", 0 },
{},
@@ -2957,12 +3060,12 @@ MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match);
static struct platform_driver arm_sbsa_uart_platform_driver = {
.probe = sbsa_uart_probe,
- .remove_new = sbsa_uart_remove,
+ .remove = sbsa_uart_remove,
.driver = {
.name = "sbsa-uart",
.pm = &pl011_dev_pm_ops,
- .of_match_table = of_match_ptr(sbsa_uart_of_match),
- .acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match),
+ .of_match_table = sbsa_uart_of_match,
+ .acpi_match_table = sbsa_uart_acpi_match,
.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
},
};
diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c
index 7790cbc57391..8bb33556b312 100644
--- a/drivers/tty/serial/ar933x_uart.c
+++ b/drivers/tty/serial/ar933x_uart.c
@@ -390,7 +390,7 @@ static void ar933x_uart_rx_chars(struct ar933x_uart_port *up)
static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
{
- struct circ_buf *xmit = &up->port.state->xmit;
+ struct tty_port *tport = &up->port.state->port;
struct serial_rs485 *rs485conf = &up->port.rs485;
int count;
bool half_duplex_send = false;
@@ -399,7 +399,7 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
return;
if ((rs485conf->flags & SER_RS485_ENABLED) &&
- (up->port.x_char || !uart_circ_empty(xmit))) {
+ (up->port.x_char || !kfifo_is_empty(&tport->xmit_fifo))) {
ar933x_uart_stop_rx_interrupt(up);
gpiod_set_value(up->rts_gpiod, !!(rs485conf->flags & SER_RS485_RTS_ON_SEND));
half_duplex_send = true;
@@ -408,6 +408,7 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
count = up->port.fifosize;
do {
unsigned int rdata;
+ unsigned char c;
rdata = ar933x_uart_read(up, AR933X_UART_DATA_REG);
if ((rdata & AR933X_UART_DATA_TX_CSR) == 0)
@@ -420,18 +421,16 @@ static void ar933x_uart_tx_chars(struct ar933x_uart_port *up)
continue;
}
- if (uart_circ_empty(xmit))
+ if (!uart_fifo_get(&up->port, &c))
break;
- ar933x_uart_putc(up, xmit->buf[xmit->tail]);
-
- uart_xmit_advance(&up->port, 1);
+ ar933x_uart_putc(up, c);
} while (--count > 0);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
- if (!uart_circ_empty(xmit)) {
+ if (!kfifo_is_empty(&tport->xmit_fifo)) {
ar933x_uart_start_tx_interrupt(up);
} else if (half_duplex_send) {
ar933x_uart_wait_tx_complete(up);
@@ -693,7 +692,6 @@ static struct uart_driver ar933x_uart_driver = {
.cons = NULL, /* filled in runtime */
};
-static const struct serial_rs485 ar933x_no_rs485 = {};
static const struct serial_rs485 ar933x_rs485_supported = {
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
};
@@ -789,7 +787,7 @@ static int ar933x_uart_probe(struct platform_device *pdev)
up->rts_gpiod = mctrl_gpio_to_gpiod(up->gpios, UART_GPIO_RTS);
if (!up->rts_gpiod) {
- port->rs485_supported = ar933x_no_rs485;
+ port->rs485_supported.flags &= ~SER_RS485_ENABLED;
if (port->rs485.flags & SER_RS485_ENABLED) {
dev_err(&pdev->dev, "lacking rts-gpio, disabling RS485\n");
port->rs485.flags &= ~SER_RS485_ENABLED;
@@ -834,7 +832,7 @@ MODULE_DEVICE_TABLE(of, ar933x_uart_of_ids);
static struct platform_driver ar933x_uart_platform_driver = {
.probe = ar933x_uart_probe,
- .remove_new = ar933x_uart_remove,
+ .remove = ar933x_uart_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(ar933x_uart_of_ids),
diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c
index 1aa5b2b49c26..5c4895d154c0 100644
--- a/drivers/tty/serial/arc_uart.c
+++ b/drivers/tty/serial/arc_uart.c
@@ -155,7 +155,7 @@ static unsigned int arc_serial_tx_empty(struct uart_port *port)
*/
static void arc_serial_tx_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
int sent = 0;
unsigned char ch;
@@ -164,9 +164,7 @@ static void arc_serial_tx_chars(struct uart_port *port)
port->icount.tx++;
port->x_char = 0;
sent = 1;
- } else if (!uart_circ_empty(xmit)) {
- ch = xmit->buf[xmit->tail];
- uart_xmit_advance(port, 1);
+ } else if (uart_fifo_get(port, &ch)) {
while (!(UART_GET_STATUS(port) & TXEMPTY))
cpu_relax();
UART_SET_DATA(port, ch);
@@ -177,7 +175,7 @@ static void arc_serial_tx_chars(struct uart_port *port)
* If num chars in xmit buffer are too few, ask tty layer for more.
* By Hard ISR to schedule processing in software interrupt part
*/
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
if (sent)
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 85667f709515..18dba502144d 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -96,7 +96,9 @@ struct atmel_uart_char {
* can contain up to 1024 characters in PIO mode and up to 4096 characters in
* DMA mode.
*/
-#define ATMEL_SERIAL_RINGSIZE 1024
+#define ATMEL_SERIAL_RINGSIZE 1024
+#define ATMEL_SERIAL_RX_SIZE array_size(sizeof(struct atmel_uart_char), \
+ ATMEL_SERIAL_RINGSIZE)
/*
* at91: 6 USARTs and one DBGU port (SAM9260)
@@ -132,8 +134,8 @@ struct atmel_uart_port {
struct dma_async_tx_descriptor *desc_rx;
dma_cookie_t cookie_tx;
dma_cookie_t cookie_rx;
- struct scatterlist sg_tx;
- struct scatterlist sg_rx;
+ dma_addr_t tx_phys;
+ dma_addr_t rx_phys;
struct tasklet_struct tasklet_rx;
struct tasklet_struct tasklet_tx;
atomic_t tasklet_shutdown;
@@ -698,7 +700,7 @@ static void atmel_disable_ms(struct uart_port *port)
atmel_port->ms_irq_enabled = false;
- mctrl_gpio_disable_ms(atmel_port->gpios);
+ mctrl_gpio_disable_ms_no_sync(atmel_port->gpios);
if (!mctrl_gpio_to_gpiod(atmel_port->gpios, UART_GPIO_CTS))
idr |= ATMEL_US_CTSIC;
@@ -857,7 +859,7 @@ static void atmel_complete_tx_dma(void *arg)
{
struct atmel_uart_port *atmel_port = arg;
struct uart_port *port = &atmel_port->uart;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
struct dma_chan *chan = atmel_port->chan_tx;
unsigned long flags;
@@ -873,15 +875,15 @@ static void atmel_complete_tx_dma(void *arg)
atmel_port->desc_tx = NULL;
spin_unlock(&atmel_port->lock_tx);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
/*
- * xmit is a circular buffer so, if we have just send data from
- * xmit->tail to the end of xmit->buf, now we have to transmit the
- * remaining data from the beginning of xmit->buf to xmit->head.
+ * xmit is a circular buffer so, if we have just send data from the
+ * tail to the end, now we have to transmit the remaining data from the
+ * beginning to the head.
*/
- if (!uart_circ_empty(xmit))
+ if (!kfifo_is_empty(&tport->xmit_fifo))
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
else if (atmel_uart_is_half_duplex(port)) {
/*
@@ -904,8 +906,8 @@ static void atmel_release_tx_dma(struct uart_port *port)
if (chan) {
dmaengine_terminate_all(chan);
dma_release_channel(chan);
- dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1,
- DMA_TO_DEVICE);
+ dma_unmap_single(port->dev, atmel_port->tx_phys,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
}
atmel_port->desc_tx = NULL;
@@ -919,18 +921,18 @@ static void atmel_release_tx_dma(struct uart_port *port)
static void atmel_tx_dma(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
struct dma_chan *chan = atmel_port->chan_tx;
struct dma_async_tx_descriptor *desc;
- struct scatterlist sgl[2], *sg, *sg_tx = &atmel_port->sg_tx;
- unsigned int tx_len, part1_len, part2_len, sg_len;
+ struct scatterlist sgl[2], *sg;
+ unsigned int tx_len, tail, part1_len, part2_len, sg_len;
dma_addr_t phys_addr;
/* Make sure we have an idle channel */
if (atmel_port->desc_tx != NULL)
return;
- if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
+ if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) {
/*
* DMA is idle now.
* Port xmit buffer is already mapped,
@@ -940,9 +942,8 @@ static void atmel_tx_dma(struct uart_port *port)
* Take the port lock to get a
* consistent xmit buffer state.
*/
- tx_len = CIRC_CNT_TO_END(xmit->head,
- xmit->tail,
- UART_XMIT_SIZE);
+ tx_len = kfifo_out_linear(&tport->xmit_fifo, &tail,
+ UART_XMIT_SIZE);
if (atmel_port->fifo_size) {
/* multi data mode */
@@ -956,7 +957,7 @@ static void atmel_tx_dma(struct uart_port *port)
sg_init_table(sgl, 2);
sg_len = 0;
- phys_addr = sg_dma_address(sg_tx) + xmit->tail;
+ phys_addr = atmel_port->tx_phys + tail;
if (part1_len) {
sg = &sgl[sg_len++];
sg_dma_address(sg) = phys_addr;
@@ -973,7 +974,7 @@ static void atmel_tx_dma(struct uart_port *port)
/*
* save tx_len so atmel_complete_tx_dma() will increase
- * xmit->tail correctly
+ * tail correctly
*/
atmel_port->tx_len = tx_len;
@@ -988,7 +989,8 @@ static void atmel_tx_dma(struct uart_port *port)
return;
}
- dma_sync_sg_for_device(port->dev, sg_tx, 1, DMA_TO_DEVICE);
+ dma_sync_single_for_device(port->dev, atmel_port->tx_phys,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
atmel_port->desc_tx = desc;
desc->callback = atmel_complete_tx_dma;
@@ -1003,18 +1005,19 @@ static void atmel_tx_dma(struct uart_port *port)
dma_async_issue_pending(chan);
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
static int atmel_prepare_tx_dma(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ struct tty_port *tport = &port->state->port;
struct device *mfd_dev = port->dev->parent;
dma_cap_mask_t mask;
struct dma_slave_config config;
struct dma_chan *chan;
- int ret, nent;
+ int ret;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
@@ -1029,26 +1032,18 @@ static int atmel_prepare_tx_dma(struct uart_port *port)
dma_chan_name(atmel_port->chan_tx));
spin_lock_init(&atmel_port->lock_tx);
- sg_init_table(&atmel_port->sg_tx, 1);
/* UART circular tx buffer is an aligned page. */
- BUG_ON(!PAGE_ALIGNED(port->state->xmit.buf));
- sg_set_page(&atmel_port->sg_tx,
- virt_to_page(port->state->xmit.buf),
- UART_XMIT_SIZE,
- offset_in_page(port->state->xmit.buf));
- nent = dma_map_sg(port->dev,
- &atmel_port->sg_tx,
- 1,
- DMA_TO_DEVICE);
-
- if (!nent) {
+ BUG_ON(!PAGE_ALIGNED(tport->xmit_buf));
+ atmel_port->tx_phys = dma_map_single(port->dev, tport->xmit_buf,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+ if (dma_mapping_error(port->dev, atmel_port->tx_phys)) {
dev_dbg(port->dev, "need to release resource of dma\n");
goto chan_err;
} else {
- dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
- sg_dma_len(&atmel_port->sg_tx),
- port->state->xmit.buf,
- &sg_dma_address(&atmel_port->sg_tx));
+ dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n", __func__,
+ UART_XMIT_SIZE, tport->xmit_buf,
+ &atmel_port->tx_phys);
}
/* Configure the slave DMA */
@@ -1093,8 +1088,8 @@ static void atmel_release_rx_dma(struct uart_port *port)
if (chan) {
dmaengine_terminate_all(chan);
dma_release_channel(chan);
- dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1,
- DMA_FROM_DEVICE);
+ dma_unmap_single(port->dev, atmel_port->rx_phys,
+ ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE);
}
atmel_port->desc_rx = NULL;
@@ -1127,10 +1122,8 @@ static void atmel_rx_from_dma(struct uart_port *port)
}
/* CPU claims ownership of RX DMA buffer */
- dma_sync_sg_for_cpu(port->dev,
- &atmel_port->sg_rx,
- 1,
- DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(port->dev, atmel_port->rx_phys,
+ ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE);
/*
* ring->head points to the end of data already written by the DMA.
@@ -1139,8 +1132,8 @@ static void atmel_rx_from_dma(struct uart_port *port)
* The current transfer size should not be larger than the dma buffer
* length.
*/
- ring->head = sg_dma_len(&atmel_port->sg_rx) - state.residue;
- BUG_ON(ring->head > sg_dma_len(&atmel_port->sg_rx));
+ ring->head = ATMEL_SERIAL_RX_SIZE - state.residue;
+ BUG_ON(ring->head > ATMEL_SERIAL_RX_SIZE);
/*
* At this point ring->head may point to the first byte right after the
* last byte of the dma buffer:
@@ -1154,7 +1147,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
* tail to the end of the buffer then reset tail.
*/
if (ring->head < ring->tail) {
- count = sg_dma_len(&atmel_port->sg_rx) - ring->tail;
+ count = ATMEL_SERIAL_RX_SIZE - ring->tail;
tty_insert_flip_string(tport, ring->buf + ring->tail, count);
ring->tail = 0;
@@ -1167,17 +1160,15 @@ static void atmel_rx_from_dma(struct uart_port *port)
tty_insert_flip_string(tport, ring->buf + ring->tail, count);
/* Wrap ring->head if needed */
- if (ring->head >= sg_dma_len(&atmel_port->sg_rx))
+ if (ring->head >= ATMEL_SERIAL_RX_SIZE)
ring->head = 0;
ring->tail = ring->head;
port->icount.rx += count;
}
- /* USART retreives ownership of RX DMA buffer */
- dma_sync_sg_for_device(port->dev,
- &atmel_port->sg_rx,
- 1,
- DMA_FROM_DEVICE);
+ /* USART retrieves ownership of RX DMA buffer */
+ dma_sync_single_for_device(port->dev, atmel_port->rx_phys,
+ ATMEL_SERIAL_RX_SIZE, DMA_FROM_DEVICE);
tty_flip_buffer_push(tport);
@@ -1193,7 +1184,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
struct dma_slave_config config;
struct circ_buf *ring;
struct dma_chan *chan;
- int ret, nent;
+ int ret;
ring = &atmel_port->rx_ring;
@@ -1210,26 +1201,18 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
dma_chan_name(atmel_port->chan_rx));
spin_lock_init(&atmel_port->lock_rx);
- sg_init_table(&atmel_port->sg_rx, 1);
/* UART circular rx buffer is an aligned page. */
BUG_ON(!PAGE_ALIGNED(ring->buf));
- sg_set_page(&atmel_port->sg_rx,
- virt_to_page(ring->buf),
- sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE,
- offset_in_page(ring->buf));
- nent = dma_map_sg(port->dev,
- &atmel_port->sg_rx,
- 1,
- DMA_FROM_DEVICE);
-
- if (!nent) {
+ atmel_port->rx_phys = dma_map_single(port->dev, ring->buf,
+ ATMEL_SERIAL_RX_SIZE,
+ DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(port->dev, atmel_port->rx_phys)) {
dev_dbg(port->dev, "need to release resource of dma\n");
goto chan_err;
} else {
- dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", __func__,
- sg_dma_len(&atmel_port->sg_rx),
- ring->buf,
- &sg_dma_address(&atmel_port->sg_rx));
+ dev_dbg(port->dev, "%s: mapped %zu@%p to %pad\n", __func__,
+ ATMEL_SERIAL_RX_SIZE, ring->buf, &atmel_port->rx_phys);
}
/* Configure the slave DMA */
@@ -1250,9 +1233,9 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
* each one is half ring buffer size
*/
desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx,
- sg_dma_address(&atmel_port->sg_rx),
- sg_dma_len(&atmel_port->sg_rx),
- sg_dma_len(&atmel_port->sg_rx)/2,
+ atmel_port->rx_phys,
+ ATMEL_SERIAL_RX_SIZE,
+ ATMEL_SERIAL_RX_SIZE / 2,
DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (!desc) {
@@ -1459,9 +1442,8 @@ static void atmel_release_tx_pdc(struct uart_port *port)
static void atmel_tx_pdc(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
- int count;
/* nothing left to transmit? */
if (atmel_uart_readl(port, ATMEL_PDC_TCR))
@@ -1474,17 +1456,19 @@ static void atmel_tx_pdc(struct uart_port *port)
/* disable PDC transmit */
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS);
- if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
+ if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) {
+ unsigned int count, tail;
+
dma_sync_single_for_device(port->dev,
pdc->dma_addr,
pdc->dma_size,
DMA_TO_DEVICE);
- count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ count = kfifo_out_linear(&tport->xmit_fifo, &tail,
+ UART_XMIT_SIZE);
pdc->ofs = count;
- atmel_uart_writel(port, ATMEL_PDC_TPR,
- pdc->dma_addr + xmit->tail);
+ atmel_uart_writel(port, ATMEL_PDC_TPR, pdc->dma_addr + tail);
atmel_uart_writel(port, ATMEL_PDC_TCR, count);
/* re-enable PDC transmit */
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
@@ -1498,7 +1482,7 @@ static void atmel_tx_pdc(struct uart_port *port)
}
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
@@ -1506,9 +1490,9 @@ static int atmel_prepare_tx_pdc(struct uart_port *port)
{
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
- pdc->buf = xmit->buf;
+ pdc->buf = tport->xmit_buf;
pdc->dma_addr = dma_map_single(port->dev,
pdc->buf,
UART_XMIT_SIZE,
@@ -1743,26 +1727,16 @@ static void atmel_init_property(struct atmel_uart_port *atmel_port,
/* DMA/PDC usage specification */
if (of_property_read_bool(np, "atmel,use-dma-rx")) {
- if (of_property_read_bool(np, "dmas")) {
- atmel_port->use_dma_rx = true;
- atmel_port->use_pdc_rx = false;
- } else {
- atmel_port->use_dma_rx = false;
- atmel_port->use_pdc_rx = true;
- }
+ atmel_port->use_dma_rx = of_property_present(np, "dmas");
+ atmel_port->use_pdc_rx = !atmel_port->use_dma_rx;
} else {
atmel_port->use_dma_rx = false;
atmel_port->use_pdc_rx = false;
}
if (of_property_read_bool(np, "atmel,use-dma-tx")) {
- if (of_property_read_bool(np, "dmas")) {
- atmel_port->use_dma_tx = true;
- atmel_port->use_pdc_tx = false;
- } else {
- atmel_port->use_dma_tx = false;
- atmel_port->use_pdc_tx = true;
- }
+ atmel_port->use_dma_tx = of_property_present(np, "dmas");
+ atmel_port->use_pdc_tx = !atmel_port->use_dma_tx;
} else {
atmel_port->use_dma_tx = false;
atmel_port->use_pdc_tx = false;
@@ -2043,7 +2017,7 @@ static void atmel_shutdown(struct uart_port *port)
* Prevent any tasklets being scheduled during
* cleanup
*/
- del_timer_sync(&atmel_port->uart_timer);
+ timer_delete_sync(&atmel_port->uart_timer);
/* Make sure that no interrupt is on the fly */
synchronize_irq(port->irq);
@@ -2435,17 +2409,11 @@ static void atmel_release_port(struct uart_port *port)
static int atmel_request_port(struct uart_port *port)
{
struct platform_device *mpdev = to_platform_device(port->dev->parent);
- int size = resource_size(mpdev->resource);
-
- if (!request_mem_region(port->mapbase, size, "atmel_serial"))
- return -EBUSY;
if (port->flags & UPF_IOREMAP) {
- port->membase = ioremap(port->mapbase, size);
- if (port->membase == NULL) {
- release_mem_region(port->mapbase, size);
- return -ENOMEM;
- }
+ port->membase = devm_platform_ioremap_resource(mpdev, 0);
+ if (IS_ERR(port->membase))
+ return PTR_ERR(port->membase);
}
return 0;
@@ -2530,7 +2498,7 @@ static const struct uart_ops atmel_pops = {
};
static const struct serial_rs485 atmel_rs485_supported = {
- .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND | SER_RS485_RX_DURING_TX,
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX,
.delay_rts_before_send = 1,
.delay_rts_after_send = 1,
};
@@ -2953,9 +2921,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
if (!atmel_use_pdc_rx(&atmel_port->uart)) {
ret = -ENOMEM;
- data = kmalloc_array(ATMEL_SERIAL_RINGSIZE,
- sizeof(struct atmel_uart_char),
- GFP_KERNEL);
+ data = kmalloc(ATMEL_SERIAL_RX_SIZE, GFP_KERNEL);
if (!data)
goto err_clk_disable_unprepare;
atmel_port->rx_ring.buf = data;
@@ -3035,7 +3001,7 @@ static SIMPLE_DEV_PM_OPS(atmel_serial_pm_ops, atmel_serial_suspend,
static struct platform_driver atmel_serial_driver = {
.probe = atmel_serial_probe,
- .remove_new = atmel_serial_remove,
+ .remove = atmel_serial_remove,
.driver = {
.name = "atmel_usart_serial",
.of_match_table = of_match_ptr(atmel_serial_dt_ids),
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index 34801a6f300b..51df9d2d8bfc 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -308,8 +308,8 @@ static void bcm_uart_do_tx(struct uart_port *port)
val = bcm_uart_readl(port, UART_MCTL_REG);
val = (val & UART_MCTL_TXFIFOFILL_MASK) >> UART_MCTL_TXFIFOFILL_SHIFT;
-
- pending = uart_port_tx_limited(port, ch, port->fifosize - val,
+ pending = uart_port_tx_limited_flags(port, ch, UART_TX_NOSTOP,
+ port->fifosize - val,
true,
bcm_uart_writel(port, ch, UART_FIFO_REG),
({}));
@@ -320,6 +320,9 @@ static void bcm_uart_do_tx(struct uart_port *port)
val = bcm_uart_readl(port, UART_IR_REG);
val &= ~UART_TX_INT_MASK;
bcm_uart_writel(port, val, UART_IR_REG);
+
+ if (uart_tx_stopped(port))
+ bcm_uart_stop_tx(port);
}
/*
@@ -881,7 +884,7 @@ MODULE_DEVICE_TABLE(of, bcm63xx_of_match);
*/
static struct platform_driver bcm_uart_platform_driver = {
.probe = bcm_uart_probe,
- .remove_new = bcm_uart_remove,
+ .remove = bcm_uart_remove,
.driver = {
.name = "bcm63xx_uart",
.of_match_table = bcm63xx_of_match,
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 7927725b8957..83186bf50002 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -146,7 +146,8 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct clps711x_port *s = dev_get_drvdata(port->dev);
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
+ unsigned char c;
if (port->x_char) {
writew(port->x_char, port->membase + UARTDR_OFFSET);
@@ -155,7 +156,7 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
return IRQ_HANDLED;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
if (s->tx_enabled) {
disable_irq_nosync(port->irq);
s->tx_enabled = 0;
@@ -163,18 +164,17 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
return IRQ_HANDLED;
}
- while (!uart_circ_empty(xmit)) {
+ while (uart_fifo_get(port, &c)) {
u32 sysflg = 0;
- writew(xmit->buf[xmit->tail], port->membase + UARTDR_OFFSET);
- uart_xmit_advance(port, 1);
+ writew(c, port->membase + UARTDR_OFFSET);
regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg);
if (sysflg & SYSFLG_UTXFF)
break;
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
return IRQ_HANDLED;
@@ -529,7 +529,7 @@ static struct platform_driver clps711x_uart_platform = {
.of_match_table = of_match_ptr(clps711x_uart_dt_ids),
},
.probe = uart_clps711x_probe,
- .remove_new = uart_clps711x_remove,
+ .remove = uart_clps711x_remove,
};
static int __init uart_clps711x_init(void)
diff --git a/drivers/tty/serial/cpm_uart.c b/drivers/tty/serial/cpm_uart.c
index df56c6c5afd0..b778a20ec9b1 100644
--- a/drivers/tty/serial/cpm_uart.c
+++ b/drivers/tty/serial/cpm_uart.c
@@ -631,7 +631,7 @@ static int cpm_uart_verify_port(struct uart_port *port,
if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
ret = -EINVAL;
- if (ser->irq < 0 || ser->irq >= nr_irqs)
+ if (ser->irq < 0 || ser->irq >= irq_get_nr_irqs())
ret = -EINVAL;
if (ser->baud_base < 9600)
ret = -EINVAL;
@@ -648,7 +648,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
int count;
struct uart_cpm_port *pinfo =
container_of(port, struct uart_cpm_port, port);
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
/* Handle xon/xoff */
if (port->x_char) {
@@ -673,7 +673,7 @@ static int cpm_uart_tx_pump(struct uart_port *port)
return 1;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
cpm_uart_stop_tx(port);
return 0;
}
@@ -681,16 +681,10 @@ static int cpm_uart_tx_pump(struct uart_port *port)
/* Pick next descriptor and fill from buffer */
bdp = pinfo->tx_cur;
- while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) && !uart_circ_empty(xmit)) {
- count = 0;
+ while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) &&
+ !kfifo_is_empty(&tport->xmit_fifo)) {
p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
- while (count < pinfo->tx_fifosize) {
- *p++ = xmit->buf[xmit->tail];
- uart_xmit_advance(port, 1);
- count++;
- if (uart_circ_empty(xmit))
- break;
- }
+ count = uart_fifo_out(port, p, pinfo->tx_fifosize);
out_be16(&bdp->cbd_datlen, count);
setbits16(&bdp->cbd_sc, BD_SC_READY);
/* Get next BD. */
@@ -701,10 +695,10 @@ static int cpm_uart_tx_pump(struct uart_port *port)
}
pinfo->tx_cur = bdp;
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit)) {
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
cpm_uart_stop_tx(port);
return 0;
}
@@ -1579,7 +1573,7 @@ static struct platform_driver cpm_uart_driver = {
.of_match_table = cpm_uart_match,
},
.probe = cpm_uart_probe,
- .remove_new = cpm_uart_remove,
+ .remove = cpm_uart_remove,
};
static int __init cpm_uart_init(void)
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
index e419c4bde8b7..d2482df5cb9b 100644
--- a/drivers/tty/serial/digicolor-usart.c
+++ b/drivers/tty/serial/digicolor-usart.c
@@ -179,8 +179,9 @@ static void digicolor_uart_rx(struct uart_port *port)
static void digicolor_uart_tx(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
unsigned long flags;
+ unsigned char c;
if (digicolor_uart_tx_full(port))
return;
@@ -194,20 +195,19 @@ static void digicolor_uart_tx(struct uart_port *port)
goto out;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
digicolor_uart_stop_tx(port);
goto out;
}
- while (!uart_circ_empty(xmit)) {
- writeb(xmit->buf[xmit->tail], port->membase + UA_EMI_REC);
- uart_xmit_advance(port, 1);
+ while (uart_fifo_get(port, &c)) {
+ writeb(c, port->membase + UA_EMI_REC);
if (digicolor_uart_tx_full(port))
break;
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
out:
@@ -522,7 +522,7 @@ static struct platform_driver digicolor_uart_platform = {
.of_match_table = of_match_ptr(digicolor_uart_dt_ids),
},
.probe = digicolor_uart_probe,
- .remove_new = digicolor_uart_remove,
+ .remove = digicolor_uart_remove,
};
static int __init digicolor_uart_init(void)
diff --git a/drivers/tty/serial/dz.c b/drivers/tty/serial/dz.c
index 6df7af9edc1c..eba91daedef8 100644
--- a/drivers/tty/serial/dz.c
+++ b/drivers/tty/serial/dz.c
@@ -252,13 +252,13 @@ static inline void dz_receive_chars(struct dz_mux *mux)
static inline void dz_transmit_chars(struct dz_mux *mux)
{
struct dz_port *dport = &mux->dport[0];
- struct circ_buf *xmit;
+ struct tty_port *tport;
unsigned char tmp;
u16 status;
status = dz_in(dport, DZ_CSR);
dport = &mux->dport[LINE(status)];
- xmit = &dport->port.state->xmit;
+ tport = &dport->port.state->port;
if (dport->port.x_char) { /* XON/XOFF chars */
dz_out(dport, DZ_TDR, dport->port.x_char);
@@ -267,7 +267,8 @@ static inline void dz_transmit_chars(struct dz_mux *mux)
return;
}
/* If nothing to do or stopped or hardware stopped. */
- if (uart_circ_empty(xmit) || uart_tx_stopped(&dport->port)) {
+ if (uart_tx_stopped(&dport->port) ||
+ !uart_fifo_get(&dport->port, &tmp)) {
uart_port_lock(&dport->port);
dz_stop_tx(&dport->port);
uart_port_unlock(&dport->port);
@@ -278,15 +279,13 @@ static inline void dz_transmit_chars(struct dz_mux *mux)
* If something to do... (remember the dz has no output fifo,
* so we go one char at a time) :-<
*/
- tmp = xmit->buf[xmit->tail];
dz_out(dport, DZ_TDR, tmp);
- uart_xmit_advance(&dport->port, 1);
- if (uart_circ_chars_pending(xmit) < DZ_WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < DZ_WAKEUP_CHARS)
uart_write_wakeup(&dport->port);
/* Are we are done. */
- if (uart_circ_empty(xmit)) {
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
uart_port_lock(&dport->port);
dz_stop_tx(&dport->port);
uart_port_unlock(&dport->port);
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index a5fbb6ed38ae..ab9af37f6cda 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -248,6 +248,29 @@ static int __init param_setup_earlycon(char *buf)
}
early_param("earlycon", param_setup_earlycon);
+/*
+ * The `console` parameter is overloaded. It's handled here as an early param
+ * and in `printk.c` as a late param. It's possible to specify an early
+ * `bootconsole` using `earlycon=uartXXXX` (handled above), or via
+ * the `console=uartXXX` alias. See the comment in `8250_early.c`.
+ */
+static int __init param_setup_earlycon_console_alias(char *buf)
+{
+ /*
+ * A plain `console` parameter must not enable the SPCR `bootconsole`
+ * like a plain `earlycon` does.
+ *
+ * A `console=` parameter that specifies an empty value is used to
+ * disable the `console`, not the `earlycon` `bootconsole`. The
+ * disabling of the `console` is handled by `printk.c`.
+ */
+ if (!buf || !buf[0])
+ return 0;
+
+ return param_setup_earlycon(buf);
+}
+early_param("console", param_setup_earlycon_console_alias);
+
#ifdef CONFIG_OF_EARLY_FLATTREE
int __init of_setup_earlycon(const struct earlycon_id *match,
diff --git a/drivers/tty/serial/esp32_acm.c b/drivers/tty/serial/esp32_acm.c
index d4e8bdb1cdef..bb7cc65427f0 100644
--- a/drivers/tty/serial/esp32_acm.c
+++ b/drivers/tty/serial/esp32_acm.c
@@ -423,7 +423,7 @@ static void esp32s3_acm_remove(struct platform_device *pdev)
static struct platform_driver esp32s3_acm_driver = {
.probe = esp32s3_acm_probe,
- .remove_new = esp32s3_acm_remove,
+ .remove = esp32s3_acm_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = esp32s3_acm_dt_ids,
@@ -455,4 +455,5 @@ module_init(esp32s3_acm_init);
module_exit(esp32s3_acm_exit);
MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
+MODULE_DESCRIPTION("Espressif ESP32 USB ACM gadget support");
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/esp32_uart.c b/drivers/tty/serial/esp32_uart.c
index 6fc61f323355..667c2198a03a 100644
--- a/drivers/tty/serial/esp32_uart.c
+++ b/drivers/tty/serial/esp32_uart.c
@@ -743,7 +743,7 @@ static void esp32_uart_remove(struct platform_device *pdev)
static struct platform_driver esp32_uart_driver = {
.probe = esp32_uart_probe,
- .remove_new = esp32_uart_remove,
+ .remove = esp32_uart_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = esp32_uart_dt_ids,
@@ -775,4 +775,5 @@ module_init(esp32_uart_init);
module_exit(esp32_uart_exit);
MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
+MODULE_DESCRIPTION("Espressif ESP32 UART support");
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index 5426322b5f0c..e70a56de1fce 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -174,17 +174,18 @@ static void linflex_put_char(struct uart_port *sport, unsigned char c)
static inline void linflex_transmit_buffer(struct uart_port *sport)
{
- struct circ_buf *xmit = &sport->state->xmit;
+ struct tty_port *tport = &sport->state->port;
+ unsigned char c;
- while (!uart_circ_empty(xmit)) {
- linflex_put_char(sport, xmit->buf[xmit->tail]);
- uart_xmit_advance(sport, 1);
+ while (uart_fifo_get(sport, &c)) {
+ linflex_put_char(sport, c);
+ sport->icount.tx++;
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(sport);
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
linflex_stop_tx(sport);
}
@@ -200,7 +201,7 @@ static void linflex_start_tx(struct uart_port *port)
static irqreturn_t linflex_txint(int irq, void *dev_id)
{
struct uart_port *sport = dev_id;
- struct circ_buf *xmit = &sport->state->xmit;
+ struct tty_port *tport = &sport->state->port;
unsigned long flags;
uart_port_lock_irqsave(sport, &flags);
@@ -210,7 +211,7 @@ static irqreturn_t linflex_txint(int irq, void *dev_id)
goto out;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(sport)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(sport)) {
linflex_stop_tx(sport);
goto out;
}
@@ -881,7 +882,7 @@ static SIMPLE_DEV_PM_OPS(linflex_pm_ops, linflex_suspend, linflex_resume);
static struct platform_driver linflex_driver = {
.probe = linflex_probe,
- .remove_new = linflex_remove,
+ .remove = linflex_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = linflex_dt_ids,
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index bbcbc91482af..fe5aed99d55a 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -7,6 +7,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/circ_buf.h>
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/delay.h>
@@ -183,6 +184,7 @@
#define UARTCTRL_SBK 0x00010000
#define UARTCTRL_MA1IE 0x00008000
#define UARTCTRL_MA2IE 0x00004000
+#define UARTCTRL_M7 0x00000800
#define UARTCTRL_IDLECFG GENMASK(10, 8)
#define UARTCTRL_LOOPS 0x00000080
#define UARTCTRL_DOZEEN 0x00000040
@@ -243,7 +245,7 @@
#define DRIVER_NAME "fsl-lpuart"
#define DEV_NAME "ttyLP"
-#define UART_NR 8
+#define UART_NR 12
/* IMX lpuart has four extra unused regs located at the beginning */
#define IMX_REG_OFF 0x10
@@ -439,41 +441,41 @@ static unsigned int lpuart_get_baud_clk_rate(struct lpuart_port *sport)
static void lpuart_stop_tx(struct uart_port *port)
{
- unsigned char temp;
+ u8 cr2;
- temp = readb(port->membase + UARTCR2);
- temp &= ~(UARTCR2_TIE | UARTCR2_TCIE);
- writeb(temp, port->membase + UARTCR2);
+ cr2 = readb(port->membase + UARTCR2);
+ cr2 &= ~(UARTCR2_TIE | UARTCR2_TCIE);
+ writeb(cr2, port->membase + UARTCR2);
}
static void lpuart32_stop_tx(struct uart_port *port)
{
- unsigned long temp;
+ u32 ctrl;
- temp = lpuart32_read(port, UARTCTRL);
- temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE);
- lpuart32_write(port, temp, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
+ ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE);
+ lpuart32_write(port, ctrl, UARTCTRL);
}
static void lpuart_stop_rx(struct uart_port *port)
{
- unsigned char temp;
+ u8 cr2;
- temp = readb(port->membase + UARTCR2);
- writeb(temp & ~UARTCR2_RE, port->membase + UARTCR2);
+ cr2 = readb(port->membase + UARTCR2);
+ writeb(cr2 & ~UARTCR2_RE, port->membase + UARTCR2);
}
static void lpuart32_stop_rx(struct uart_port *port)
{
- unsigned long temp;
+ u32 ctrl;
- temp = lpuart32_read(port, UARTCTRL);
- lpuart32_write(port, temp & ~UARTCTRL_RE, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
+ lpuart32_write(port, ctrl & ~UARTCTRL_RE, UARTCTRL);
}
static void lpuart_dma_tx(struct lpuart_port *sport)
{
- struct circ_buf *xmit = &sport->port.state->xmit;
+ struct tty_port *tport = &sport->port.state->port;
struct scatterlist *sgl = sport->tx_sgl;
struct device *dev = sport->port.dev;
struct dma_chan *chan = sport->dma_tx_chan;
@@ -482,18 +484,10 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
if (sport->dma_tx_in_progress)
return;
- sport->dma_tx_bytes = uart_circ_chars_pending(xmit);
-
- if (xmit->tail < xmit->head || xmit->head == 0) {
- sport->dma_tx_nents = 1;
- sg_init_one(sgl, xmit->buf + xmit->tail, sport->dma_tx_bytes);
- } else {
- sport->dma_tx_nents = 2;
- sg_init_table(sgl, 2);
- sg_set_buf(sgl, xmit->buf + xmit->tail,
- UART_XMIT_SIZE - xmit->tail);
- sg_set_buf(sgl + 1, xmit->buf, xmit->head);
- }
+ sg_init_table(sgl, ARRAY_SIZE(sport->tx_sgl));
+ sport->dma_tx_bytes = kfifo_len(&tport->xmit_fifo);
+ sport->dma_tx_nents = kfifo_dma_out_prepare(&tport->xmit_fifo, sgl,
+ ARRAY_SIZE(sport->tx_sgl), sport->dma_tx_bytes);
ret = dma_map_sg(chan->device->dev, sgl, sport->dma_tx_nents,
DMA_TO_DEVICE);
@@ -521,14 +515,15 @@ static void lpuart_dma_tx(struct lpuart_port *sport)
static bool lpuart_stopped_or_empty(struct uart_port *port)
{
- return uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port);
+ return kfifo_is_empty(&port->state->port.xmit_fifo) ||
+ uart_tx_stopped(port);
}
static void lpuart_dma_tx_complete(void *arg)
{
struct lpuart_port *sport = arg;
struct scatterlist *sgl = &sport->tx_sgl[0];
- struct circ_buf *xmit = &sport->port.state->xmit;
+ struct tty_port *tport = &sport->port.state->port;
struct dma_chan *chan = sport->dma_tx_chan;
unsigned long flags;
@@ -545,7 +540,7 @@ static void lpuart_dma_tx_complete(void *arg)
sport->dma_tx_in_progress = false;
uart_port_unlock_irqrestore(&sport->port, flags);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
if (waitqueue_active(&sport->dma_wait)) {
@@ -586,7 +581,7 @@ static int lpuart_dma_tx_request(struct uart_port *port)
ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig);
if (ret) {
- dev_err(sport->port.dev,
+ dev_err(port->dev,
"DMA slave config failed, err = %d\n", ret);
return ret;
}
@@ -604,7 +599,7 @@ static void lpuart_flush_buffer(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
struct dma_chan *chan = sport->dma_tx_chan;
- u32 val;
+ u32 fifo;
if (sport->lpuart_dma_tx_use) {
if (sport->dma_tx_in_progress) {
@@ -616,13 +611,13 @@ static void lpuart_flush_buffer(struct uart_port *port)
}
if (lpuart_is_32(sport)) {
- val = lpuart32_read(&sport->port, UARTFIFO);
- val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
- lpuart32_write(&sport->port, val, UARTFIFO);
+ fifo = lpuart32_read(port, UARTFIFO);
+ fifo |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
+ lpuart32_write(port, fifo, UARTFIFO);
} else {
- val = readb(sport->port.membase + UARTCFIFO);
- val |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH;
- writeb(val, sport->port.membase + UARTCFIFO);
+ fifo = readb(port->membase + UARTCFIFO);
+ fifo |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH;
+ writeb(fifo, port->membase + UARTCFIFO);
}
}
@@ -644,38 +639,36 @@ static void lpuart32_wait_bit_set(struct uart_port *port, unsigned int offset,
static int lpuart_poll_init(struct uart_port *port)
{
- struct lpuart_port *sport = container_of(port,
- struct lpuart_port, port);
unsigned long flags;
- unsigned char temp;
+ u8 fifo;
- sport->port.fifosize = 0;
+ port->fifosize = 0;
- uart_port_lock_irqsave(&sport->port, &flags);
+ uart_port_lock_irqsave(port, &flags);
/* Disable Rx & Tx */
- writeb(0, sport->port.membase + UARTCR2);
+ writeb(0, port->membase + UARTCR2);
- temp = readb(sport->port.membase + UARTPFIFO);
+ fifo = readb(port->membase + UARTPFIFO);
/* Enable Rx and Tx FIFO */
- writeb(temp | UARTPFIFO_RXFE | UARTPFIFO_TXFE,
- sport->port.membase + UARTPFIFO);
+ writeb(fifo | UARTPFIFO_RXFE | UARTPFIFO_TXFE,
+ port->membase + UARTPFIFO);
/* flush Tx and Rx FIFO */
writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
- sport->port.membase + UARTCFIFO);
+ port->membase + UARTCFIFO);
/* explicitly clear RDRF */
- if (readb(sport->port.membase + UARTSR1) & UARTSR1_RDRF) {
- readb(sport->port.membase + UARTDR);
- writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO);
+ if (readb(port->membase + UARTSR1) & UARTSR1_RDRF) {
+ readb(port->membase + UARTDR);
+ writeb(UARTSFIFO_RXUF, port->membase + UARTSFIFO);
}
- writeb(0, sport->port.membase + UARTTWFIFO);
- writeb(1, sport->port.membase + UARTRWFIFO);
+ writeb(0, port->membase + UARTTWFIFO);
+ writeb(1, port->membase + UARTRWFIFO);
/* Enable Rx and Tx */
- writeb(UARTCR2_RE | UARTCR2_TE, sport->port.membase + UARTCR2);
- uart_port_unlock_irqrestore(&sport->port, flags);
+ writeb(UARTCR2_RE | UARTCR2_TE, port->membase + UARTCR2);
+ uart_port_unlock_irqrestore(port, flags);
return 0;
}
@@ -698,33 +691,32 @@ static int lpuart_poll_get_char(struct uart_port *port)
static int lpuart32_poll_init(struct uart_port *port)
{
unsigned long flags;
- struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- u32 temp;
+ u32 fifo;
- sport->port.fifosize = 0;
+ port->fifosize = 0;
- uart_port_lock_irqsave(&sport->port, &flags);
+ uart_port_lock_irqsave(port, &flags);
/* Disable Rx & Tx */
- lpuart32_write(&sport->port, 0, UARTCTRL);
+ lpuart32_write(port, 0, UARTCTRL);
- temp = lpuart32_read(&sport->port, UARTFIFO);
+ fifo = lpuart32_read(port, UARTFIFO);
/* Enable Rx and Tx FIFO */
- lpuart32_write(&sport->port, temp | UARTFIFO_RXFE | UARTFIFO_TXFE, UARTFIFO);
+ lpuart32_write(port, fifo | UARTFIFO_RXFE | UARTFIFO_TXFE, UARTFIFO);
/* flush Tx and Rx FIFO */
- lpuart32_write(&sport->port, UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, UARTFIFO);
+ lpuart32_write(port, UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, UARTFIFO);
/* explicitly clear RDRF */
- if (lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_RDRF) {
- lpuart32_read(&sport->port, UARTDATA);
- lpuart32_write(&sport->port, UARTFIFO_RXUF, UARTFIFO);
+ if (lpuart32_read(port, UARTSTAT) & UARTSTAT_RDRF) {
+ lpuart32_read(port, UARTDATA);
+ lpuart32_write(port, UARTFIFO_RXUF, UARTFIFO);
}
/* Enable Rx and Tx */
- lpuart32_write(&sport->port, UARTCTRL_RE | UARTCTRL_TE, UARTCTRL);
- uart_port_unlock_irqrestore(&sport->port, flags);
+ lpuart32_write(port, UARTCTRL_RE | UARTCTRL_TE, UARTCTRL);
+ uart_port_unlock_irqrestore(port, flags);
return 0;
}
@@ -756,8 +748,9 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
{
- struct circ_buf *xmit = &sport->port.state->xmit;
- unsigned long txcnt;
+ struct tty_port *tport = &sport->port.state->port;
+ u32 txcnt;
+ unsigned char c;
if (sport->port.x_char) {
lpuart32_write(&sport->port, sport->port.x_char, UARTDATA);
@@ -774,18 +767,18 @@ static inline void lpuart32_transmit_buffer(struct lpuart_port *sport)
txcnt = lpuart32_read(&sport->port, UARTWATER);
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
txcnt &= UARTWATER_COUNT_MASK;
- while (!uart_circ_empty(xmit) && (txcnt < sport->txfifo_size)) {
- lpuart32_write(&sport->port, xmit->buf[xmit->tail], UARTDATA);
- uart_xmit_advance(&sport->port, 1);
+ while (txcnt < sport->txfifo_size &&
+ uart_fifo_get(&sport->port, &c)) {
+ lpuart32_write(&sport->port, c, UARTDATA);
txcnt = lpuart32_read(&sport->port, UARTWATER);
txcnt = txcnt >> UARTWATER_TXCNT_OFF;
txcnt &= UARTWATER_COUNT_MASK;
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
lpuart32_stop_tx(&sport->port);
}
@@ -793,10 +786,10 @@ static void lpuart_start_tx(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
- unsigned char temp;
+ u8 cr2;
- temp = readb(port->membase + UARTCR2);
- writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
+ cr2 = readb(port->membase + UARTCR2);
+ writeb(cr2 | UARTCR2_TIE, port->membase + UARTCR2);
if (sport->lpuart_dma_tx_use) {
if (!lpuart_stopped_or_empty(port))
@@ -810,14 +803,14 @@ static void lpuart_start_tx(struct uart_port *port)
static void lpuart32_start_tx(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- unsigned long temp;
+ u32 ctrl;
if (sport->lpuart_dma_tx_use) {
if (!lpuart_stopped_or_empty(port))
lpuart_dma_tx(sport);
} else {
- temp = lpuart32_read(port, UARTCTRL);
- lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
+ lpuart32_write(port, ctrl | UARTCTRL_TIE, UARTCTRL);
if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE)
lpuart32_transmit_buffer(sport);
@@ -843,8 +836,8 @@ static unsigned int lpuart_tx_empty(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
- unsigned char sr1 = readb(port->membase + UARTSR1);
- unsigned char sfifo = readb(port->membase + UARTSFIFO);
+ u8 sr1 = readb(port->membase + UARTSR1);
+ u8 sfifo = readb(port->membase + UARTSFIFO);
if (sport->dma_tx_in_progress)
return 0;
@@ -859,9 +852,9 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
- unsigned long stat = lpuart32_read(port, UARTSTAT);
- unsigned long sfifo = lpuart32_read(port, UARTFIFO);
- unsigned long ctrl = lpuart32_read(port, UARTCTRL);
+ u32 stat = lpuart32_read(port, UARTSTAT);
+ u32 sfifo = lpuart32_read(port, UARTFIFO);
+ u32 ctrl = lpuart32_read(port, UARTCTRL);
if (sport->dma_tx_in_progress)
return 0;
@@ -888,7 +881,7 @@ static void lpuart_rxint(struct lpuart_port *sport)
{
unsigned int flg, ignored = 0, overrun = 0;
struct tty_port *port = &sport->port.state->port;
- unsigned char rx, sr;
+ u8 rx, sr;
uart_port_lock(&sport->port);
@@ -965,7 +958,7 @@ static void lpuart32_rxint(struct lpuart_port *sport)
{
unsigned int flg, ignored = 0;
struct tty_port *port = &sport->port.state->port;
- unsigned long rx, sr;
+ u32 rx, sr;
bool is_break;
uart_port_lock(&sport->port);
@@ -1043,7 +1036,7 @@ out:
static irqreturn_t lpuart_int(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
- unsigned char sts;
+ u8 sts;
sts = readb(sport->port.membase + UARTSR1);
@@ -1117,7 +1110,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
int count, copied;
if (lpuart_is_32(sport)) {
- unsigned long sr = lpuart32_read(&sport->port, UARTSTAT);
+ u32 sr = lpuart32_read(&sport->port, UARTSTAT);
if (sr & (UARTSTAT_PE | UARTSTAT_FE)) {
/* Clear the error flags */
@@ -1129,10 +1122,10 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport)
sport->port.icount.frame++;
}
} else {
- unsigned char sr = readb(sport->port.membase + UARTSR1);
+ u8 sr = readb(sport->port.membase + UARTSR1);
if (sr & (UARTSR1_PE | UARTSR1_FE)) {
- unsigned char cr2;
+ u8 cr2;
/* Disable receiver during this operation... */
cr2 = readb(sport->port.membase + UARTCR2);
@@ -1283,7 +1276,7 @@ static void lpuart32_dma_idleint(struct lpuart_port *sport)
static irqreturn_t lpuart32_int(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
- unsigned long sts, rxcount;
+ u32 sts, rxcount;
sts = lpuart32_read(&sport->port, UARTSTAT);
rxcount = lpuart32_read(&sport->port, UARTWATER);
@@ -1415,12 +1408,12 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport)
dma_async_issue_pending(chan);
if (lpuart_is_32(sport)) {
- unsigned long temp = lpuart32_read(&sport->port, UARTBAUD);
+ u32 baud = lpuart32_read(&sport->port, UARTBAUD);
- lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD);
+ lpuart32_write(&sport->port, baud | UARTBAUD_RDMAE, UARTBAUD);
if (sport->dma_idle_int) {
- unsigned long ctrl = lpuart32_read(&sport->port, UARTCTRL);
+ u32 ctrl = lpuart32_read(&sport->port, UARTCTRL);
lpuart32_write(&sport->port, ctrl | UARTCTRL_ILIE, UARTCTRL);
}
@@ -1440,7 +1433,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
dmaengine_terminate_sync(chan);
if (!sport->dma_idle_int)
- del_timer_sync(&sport->lpuart_timer);
+ timer_delete_sync(&sport->lpuart_timer);
dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
kfree(sport->rx_ring.buf);
@@ -1453,12 +1446,9 @@ static void lpuart_dma_rx_free(struct uart_port *port)
static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485)
{
- struct lpuart_port *sport = container_of(port,
- struct lpuart_port, port);
-
- u8 modem = readb(sport->port.membase + UARTMODEM) &
+ u8 modem = readb(port->membase + UARTMODEM) &
~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE);
- writeb(modem, sport->port.membase + UARTMODEM);
+ writeb(modem, port->membase + UARTMODEM);
if (rs485->flags & SER_RS485_ENABLED) {
/* Enable auto RS-485 RTS mode */
@@ -1476,19 +1466,29 @@ static int lpuart_config_rs485(struct uart_port *port, struct ktermios *termios,
modem &= ~UARTMODEM_TXRTSPOL;
}
- writeb(modem, sport->port.membase + UARTMODEM);
+ writeb(modem, port->membase + UARTMODEM);
return 0;
}
static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485)
{
- struct lpuart_port *sport = container_of(port,
- struct lpuart_port, port);
-
- unsigned long modem = lpuart32_read(&sport->port, UARTMODIR)
+ u32 modem = lpuart32_read(port, UARTMODIR)
& ~(UARTMODIR_TXRTSPOL | UARTMODIR_TXRTSE);
- lpuart32_write(&sport->port, modem, UARTMODIR);
+ u32 ctrl;
+
+ /* TXRTSE and TXRTSPOL only can be changed when transmitter is disabled. */
+ ctrl = lpuart32_read(port, UARTCTRL);
+ if (ctrl & UARTCTRL_TE) {
+ /* wait for the transmit engine to complete */
+ lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TC);
+ lpuart32_write(port, ctrl & ~UARTCTRL_TE, UARTCTRL);
+
+ while (lpuart32_read(port, UARTCTRL) & UARTCTRL_TE)
+ cpu_relax();
+ }
+
+ lpuart32_write(port, modem, UARTMODIR);
if (rs485->flags & SER_RS485_ENABLED) {
/* Enable auto RS-485 RTS mode */
@@ -1506,17 +1506,21 @@ static int lpuart32_config_rs485(struct uart_port *port, struct ktermios *termio
modem &= ~UARTMODIR_TXRTSPOL;
}
- lpuart32_write(&sport->port, modem, UARTMODIR);
+ lpuart32_write(port, modem, UARTMODIR);
+
+ if (ctrl & UARTCTRL_TE)
+ lpuart32_write(port, ctrl, UARTCTRL);
+
return 0;
}
static unsigned int lpuart_get_mctrl(struct uart_port *port)
{
unsigned int mctrl = 0;
- u8 reg;
+ u8 cr1;
- reg = readb(port->membase + UARTCR1);
- if (reg & UARTCR1_LOOPS)
+ cr1 = readb(port->membase + UARTCR1);
+ if (cr1 & UARTCR1_LOOPS)
mctrl |= TIOCM_LOOP;
return mctrl;
@@ -1525,10 +1529,10 @@ static unsigned int lpuart_get_mctrl(struct uart_port *port)
static unsigned int lpuart32_get_mctrl(struct uart_port *port)
{
unsigned int mctrl = TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
- u32 reg;
+ u32 ctrl;
- reg = lpuart32_read(port, UARTCTRL);
- if (reg & UARTCTRL_LOOPS)
+ ctrl = lpuart32_read(port, UARTCTRL);
+ if (ctrl & UARTCTRL_LOOPS)
mctrl |= TIOCM_LOOP;
return mctrl;
@@ -1536,49 +1540,49 @@ static unsigned int lpuart32_get_mctrl(struct uart_port *port)
static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- u8 reg;
+ u8 cr1;
- reg = readb(port->membase + UARTCR1);
+ cr1 = readb(port->membase + UARTCR1);
/* for internal loopback we need LOOPS=1 and RSRC=0 */
- reg &= ~(UARTCR1_LOOPS | UARTCR1_RSRC);
+ cr1 &= ~(UARTCR1_LOOPS | UARTCR1_RSRC);
if (mctrl & TIOCM_LOOP)
- reg |= UARTCR1_LOOPS;
+ cr1 |= UARTCR1_LOOPS;
- writeb(reg, port->membase + UARTCR1);
+ writeb(cr1, port->membase + UARTCR1);
}
static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- u32 reg;
+ u32 ctrl;
- reg = lpuart32_read(port, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
/* for internal loopback we need LOOPS=1 and RSRC=0 */
- reg &= ~(UARTCTRL_LOOPS | UARTCTRL_RSRC);
+ ctrl &= ~(UARTCTRL_LOOPS | UARTCTRL_RSRC);
if (mctrl & TIOCM_LOOP)
- reg |= UARTCTRL_LOOPS;
+ ctrl |= UARTCTRL_LOOPS;
- lpuart32_write(port, reg, UARTCTRL);
+ lpuart32_write(port, ctrl, UARTCTRL);
}
static void lpuart_break_ctl(struct uart_port *port, int break_state)
{
- unsigned char temp;
+ u8 cr2;
- temp = readb(port->membase + UARTCR2) & ~UARTCR2_SBK;
+ cr2 = readb(port->membase + UARTCR2) & ~UARTCR2_SBK;
if (break_state != 0)
- temp |= UARTCR2_SBK;
+ cr2 |= UARTCR2_SBK;
- writeb(temp, port->membase + UARTCR2);
+ writeb(cr2, port->membase + UARTCR2);
}
static void lpuart32_break_ctl(struct uart_port *port, int break_state)
{
- unsigned long temp;
+ u32 ctrl;
- temp = lpuart32_read(port, UARTCTRL);
+ ctrl = lpuart32_read(port, UARTCTRL);
/*
* LPUART IP now has two known bugs, one is CTS has higher priority than the
@@ -1595,23 +1599,22 @@ static void lpuart32_break_ctl(struct uart_port *port, int break_state)
* Disable the transmitter to prevent any data from being sent out
* during break, then invert the TX line to send break.
*/
- temp &= ~UARTCTRL_TE;
- lpuart32_write(port, temp, UARTCTRL);
- temp |= UARTCTRL_TXINV;
- lpuart32_write(port, temp, UARTCTRL);
+ ctrl &= ~UARTCTRL_TE;
+ lpuart32_write(port, ctrl, UARTCTRL);
+ ctrl |= UARTCTRL_TXINV;
+ lpuart32_write(port, ctrl, UARTCTRL);
} else {
/* Disable the TXINV to turn off break and re-enable transmitter. */
- temp &= ~UARTCTRL_TXINV;
- lpuart32_write(port, temp, UARTCTRL);
- temp |= UARTCTRL_TE;
- lpuart32_write(port, temp, UARTCTRL);
+ ctrl &= ~UARTCTRL_TXINV;
+ lpuart32_write(port, ctrl, UARTCTRL);
+ ctrl |= UARTCTRL_TE;
+ lpuart32_write(port, ctrl, UARTCTRL);
}
}
static void lpuart_setup_watermark(struct lpuart_port *sport)
{
- unsigned char val, cr2;
- unsigned char cr2_saved;
+ u8 fifo, cr2, cr2_saved;
cr2 = readb(sport->port.membase + UARTCR2);
cr2_saved = cr2;
@@ -1619,8 +1622,8 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
UARTCR2_RIE | UARTCR2_RE);
writeb(cr2, sport->port.membase + UARTCR2);
- val = readb(sport->port.membase + UARTPFIFO);
- writeb(val | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
+ fifo = readb(sport->port.membase + UARTPFIFO);
+ writeb(fifo | UARTPFIFO_TXFE | UARTPFIFO_RXFE,
sport->port.membase + UARTPFIFO);
/* flush Tx and Rx FIFO */
@@ -1644,7 +1647,7 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
static void lpuart_setup_watermark_enable(struct lpuart_port *sport)
{
- unsigned char cr2;
+ u8 cr2;
lpuart_setup_watermark(sport);
@@ -1655,8 +1658,7 @@ static void lpuart_setup_watermark_enable(struct lpuart_port *sport)
static void lpuart32_setup_watermark(struct lpuart_port *sport)
{
- unsigned long val, ctrl;
- unsigned long ctrl_saved;
+ u32 val, ctrl, ctrl_saved;
ctrl = lpuart32_read(&sport->port, UARTCTRL);
ctrl_saved = ctrl;
@@ -1691,14 +1693,14 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport)
static void lpuart32_setup_watermark_enable(struct lpuart_port *sport)
{
- u32 temp;
+ u32 ctrl;
lpuart32_setup_watermark(sport);
- temp = lpuart32_read(&sport->port, UARTCTRL);
- temp |= UARTCTRL_RE | UARTCTRL_TE;
- temp |= FIELD_PREP(UARTCTRL_IDLECFG, 0x7);
- lpuart32_write(&sport->port, temp, UARTCTRL);
+ ctrl = lpuart32_read(&sport->port, UARTCTRL);
+ ctrl |= UARTCTRL_RE | UARTCTRL_TE;
+ ctrl |= FIELD_PREP(UARTCTRL_IDLECFG, 0x7);
+ lpuart32_write(&sport->port, ctrl, UARTCTRL);
}
static void rx_dma_timer_init(struct lpuart_port *sport)
@@ -1765,7 +1767,7 @@ err:
static void lpuart_rx_dma_startup(struct lpuart_port *sport)
{
int ret;
- unsigned char cr3;
+ u8 cr3;
if (uart_console(&sport->port))
goto err;
@@ -1815,16 +1817,16 @@ static void lpuart_hw_setup(struct lpuart_port *sport)
static int lpuart_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- unsigned char temp;
+ u8 fifo;
/* determine FIFO size and enable FIFO mode */
- temp = readb(sport->port.membase + UARTPFIFO);
+ fifo = readb(port->membase + UARTPFIFO);
- sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_TXSIZE_OFF) &
+ sport->txfifo_size = UARTFIFO_DEPTH((fifo >> UARTPFIFO_TXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK);
- sport->port.fifosize = sport->txfifo_size;
+ port->fifosize = sport->txfifo_size;
- sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) &
+ sport->rxfifo_size = UARTFIFO_DEPTH((fifo >> UARTPFIFO_RXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK);
lpuart_request_dma(sport);
@@ -1835,24 +1837,24 @@ static int lpuart_startup(struct uart_port *port)
static void lpuart32_hw_disable(struct lpuart_port *sport)
{
- unsigned long temp;
+ u32 ctrl;
- temp = lpuart32_read(&sport->port, UARTCTRL);
- temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE |
+ ctrl = lpuart32_read(&sport->port, UARTCTRL);
+ ctrl &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE |
UARTCTRL_TIE | UARTCTRL_TE);
- lpuart32_write(&sport->port, temp, UARTCTRL);
+ lpuart32_write(&sport->port, ctrl, UARTCTRL);
}
static void lpuart32_configure(struct lpuart_port *sport)
{
- unsigned long temp;
+ u32 ctrl;
- temp = lpuart32_read(&sport->port, UARTCTRL);
+ ctrl = lpuart32_read(&sport->port, UARTCTRL);
if (!sport->lpuart_dma_rx_use)
- temp |= UARTCTRL_RIE | UARTCTRL_ILIE;
+ ctrl |= UARTCTRL_RIE | UARTCTRL_ILIE;
if (!sport->lpuart_dma_tx_use)
- temp |= UARTCTRL_TIE;
- lpuart32_write(&sport->port, temp, UARTCTRL);
+ ctrl |= UARTCTRL_TIE;
+ lpuart32_write(&sport->port, ctrl, UARTCTRL);
}
static void lpuart32_hw_setup(struct lpuart_port *sport)
@@ -1875,16 +1877,16 @@ static void lpuart32_hw_setup(struct lpuart_port *sport)
static int lpuart32_startup(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- unsigned long temp;
+ u32 fifo;
/* determine FIFO size */
- temp = lpuart32_read(&sport->port, UARTFIFO);
+ fifo = lpuart32_read(port, UARTFIFO);
- sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_TXSIZE_OFF) &
+ sport->txfifo_size = UARTFIFO_DEPTH((fifo >> UARTFIFO_TXSIZE_OFF) &
UARTFIFO_FIFOSIZE_MASK);
- sport->port.fifosize = sport->txfifo_size;
+ port->fifosize = sport->txfifo_size;
- sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_RXSIZE_OFF) &
+ sport->rxfifo_size = UARTFIFO_DEPTH((fifo >> UARTFIFO_RXSIZE_OFF) &
UARTFIFO_FIFOSIZE_MASK);
/*
@@ -1895,7 +1897,7 @@ static int lpuart32_startup(struct uart_port *port)
if (is_layerscape_lpuart(sport)) {
sport->rxfifo_size = 16;
sport->txfifo_size = 16;
- sport->port.fifosize = sport->txfifo_size;
+ port->fifosize = sport->txfifo_size;
}
lpuart_request_dma(sport);
@@ -1929,16 +1931,16 @@ static void lpuart_dma_shutdown(struct lpuart_port *sport)
static void lpuart_shutdown(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
- unsigned char temp;
+ u8 cr2;
unsigned long flags;
uart_port_lock_irqsave(port, &flags);
/* disable Rx/Tx and interrupts */
- temp = readb(port->membase + UARTCR2);
- temp &= ~(UARTCR2_TE | UARTCR2_RE |
+ cr2 = readb(port->membase + UARTCR2);
+ cr2 &= ~(UARTCR2_TE | UARTCR2_RE |
UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE);
- writeb(temp, port->membase + UARTCR2);
+ writeb(cr2, port->membase + UARTCR2);
uart_port_unlock_irqrestore(port, flags);
@@ -1949,14 +1951,14 @@ static void lpuart32_shutdown(struct uart_port *port)
{
struct lpuart_port *sport =
container_of(port, struct lpuart_port, port);
- unsigned long temp;
+ u32 temp;
unsigned long flags;
uart_port_lock_irqsave(port, &flags);
/* clear status */
- temp = lpuart32_read(&sport->port, UARTSTAT);
- lpuart32_write(&sport->port, temp, UARTSTAT);
+ temp = lpuart32_read(port, UARTSTAT);
+ lpuart32_write(port, temp, UARTSTAT);
/* disable Rx/Tx DMA */
temp = lpuart32_read(port, UARTBAUD);
@@ -1969,6 +1971,11 @@ static void lpuart32_shutdown(struct uart_port *port)
UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_SBK);
lpuart32_write(port, temp, UARTCTRL);
+ /* flush Rx/Tx FIFO */
+ temp = lpuart32_read(port, UARTFIFO);
+ temp |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
+ lpuart32_write(port, temp, UARTFIFO);
+
uart_port_unlock_irqrestore(port, flags);
lpuart_dma_shutdown(sport);
@@ -1980,17 +1987,17 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
unsigned long flags;
- unsigned char cr1, old_cr1, old_cr2, cr3, cr4, bdh, modem;
+ u8 cr1, old_cr1, old_cr2, cr3, cr4, bdh, modem;
unsigned int baud;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
unsigned int sbr, brfa;
- cr1 = old_cr1 = readb(sport->port.membase + UARTCR1);
- old_cr2 = readb(sport->port.membase + UARTCR2);
- cr3 = readb(sport->port.membase + UARTCR3);
- cr4 = readb(sport->port.membase + UARTCR4);
- bdh = readb(sport->port.membase + UARTBDH);
- modem = readb(sport->port.membase + UARTMODEM);
+ cr1 = old_cr1 = readb(port->membase + UARTCR1);
+ old_cr2 = readb(port->membase + UARTCR2);
+ cr3 = readb(port->membase + UARTCR3);
+ cr4 = readb(port->membase + UARTCR4);
+ bdh = readb(port->membase + UARTBDH);
+ modem = readb(port->membase + UARTMODEM);
/*
* only support CS8 and CS7, and for CS7 must enable PE.
* supported mode:
@@ -2022,7 +2029,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
* When auto RS-485 RTS mode is enabled,
* hardware flow control need to be disabled.
*/
- if (sport->port.rs485.flags & SER_RS485_ENABLED)
+ if (port->rs485.flags & SER_RS485_ENABLED)
termios->c_cflag &= ~CRTSCTS;
if (termios->c_cflag & CRTSCTS)
@@ -2063,59 +2070,59 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
* Need to update the Ring buffer length according to the selected
* baud rate and restart Rx DMA path.
*
- * Since timer function acqures sport->port.lock, need to stop before
- * acquring same lock because otherwise del_timer_sync() can deadlock.
+ * Since timer function acqures port->lock, need to stop before
+ * acquring same lock because otherwise timer_delete_sync() can deadlock.
*/
if (old && sport->lpuart_dma_rx_use)
- lpuart_dma_rx_free(&sport->port);
+ lpuart_dma_rx_free(port);
- uart_port_lock_irqsave(&sport->port, &flags);
+ uart_port_lock_irqsave(port, &flags);
- sport->port.read_status_mask = 0;
+ port->read_status_mask = 0;
if (termios->c_iflag & INPCK)
- sport->port.read_status_mask |= UARTSR1_FE | UARTSR1_PE;
+ port->read_status_mask |= UARTSR1_FE | UARTSR1_PE;
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
- sport->port.read_status_mask |= UARTSR1_FE;
+ port->read_status_mask |= UARTSR1_FE;
/* characters to ignore */
- sport->port.ignore_status_mask = 0;
+ port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
- sport->port.ignore_status_mask |= UARTSR1_PE;
+ port->ignore_status_mask |= UARTSR1_PE;
if (termios->c_iflag & IGNBRK) {
- sport->port.ignore_status_mask |= UARTSR1_FE;
+ port->ignore_status_mask |= UARTSR1_FE;
/*
* if we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
- sport->port.ignore_status_mask |= UARTSR1_OR;
+ port->ignore_status_mask |= UARTSR1_OR;
}
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
/* wait transmit engin complete */
- lpuart_wait_bit_set(&sport->port, UARTSR1, UARTSR1_TC);
+ lpuart_wait_bit_set(port, UARTSR1, UARTSR1_TC);
/* disable transmit and receive */
writeb(old_cr2 & ~(UARTCR2_TE | UARTCR2_RE),
- sport->port.membase + UARTCR2);
+ port->membase + UARTCR2);
- sbr = sport->port.uartclk / (16 * baud);
- brfa = ((sport->port.uartclk - (16 * sbr * baud)) * 2) / baud;
+ sbr = port->uartclk / (16 * baud);
+ brfa = ((port->uartclk - (16 * sbr * baud)) * 2) / baud;
bdh &= ~UARTBDH_SBR_MASK;
bdh |= (sbr >> 8) & 0x1F;
cr4 &= ~UARTCR4_BRFA_MASK;
brfa &= UARTCR4_BRFA_MASK;
- writeb(cr4 | brfa, sport->port.membase + UARTCR4);
- writeb(bdh, sport->port.membase + UARTBDH);
- writeb(sbr & 0xFF, sport->port.membase + UARTBDL);
- writeb(cr3, sport->port.membase + UARTCR3);
- writeb(cr1, sport->port.membase + UARTCR1);
- writeb(modem, sport->port.membase + UARTMODEM);
+ writeb(cr4 | brfa, port->membase + UARTCR4);
+ writeb(bdh, port->membase + UARTBDH);
+ writeb(sbr & 0xFF, port->membase + UARTBDL);
+ writeb(cr3, port->membase + UARTCR3);
+ writeb(cr1, port->membase + UARTCR1);
+ writeb(modem, port->membase + UARTMODEM);
/* restore control register */
- writeb(old_cr2, sport->port.membase + UARTCR2);
+ writeb(old_cr2, port->membase + UARTCR2);
if (old && sport->lpuart_dma_rx_use) {
if (!lpuart_start_rx_dma(sport))
@@ -2124,14 +2131,14 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
sport->lpuart_dma_rx_use = false;
}
- uart_port_unlock_irqrestore(&sport->port, flags);
+ uart_port_unlock_irqrestore(port, flags);
}
static void __lpuart32_serial_setbrg(struct uart_port *port,
unsigned int baudrate, bool use_rx_dma,
bool use_tx_dma)
{
- u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, tmp;
+ u32 sbr, osr, baud_diff, tmp_osr, tmp_sbr, tmp_diff, baud;
u32 clk = port->uartclk;
/*
@@ -2160,9 +2167,9 @@ static void __lpuart32_serial_setbrg(struct uart_port *port,
tmp_diff = clk / (tmp_osr * tmp_sbr) - baudrate;
/* select best values between sbr and sbr+1 */
- tmp = clk / (tmp_osr * (tmp_sbr + 1));
- if (tmp_diff > (baudrate - tmp)) {
- tmp_diff = baudrate - tmp;
+ baud = clk / (tmp_osr * (tmp_sbr + 1));
+ if (tmp_diff > (baudrate - baud)) {
+ tmp_diff = baudrate - baud;
tmp_sbr++;
}
@@ -2184,23 +2191,23 @@ static void __lpuart32_serial_setbrg(struct uart_port *port,
dev_warn(port->dev,
"unacceptable baud rate difference of more than 3%%\n");
- tmp = lpuart32_read(port, UARTBAUD);
+ baud = lpuart32_read(port, UARTBAUD);
if ((osr > 3) && (osr < 8))
- tmp |= UARTBAUD_BOTHEDGE;
+ baud |= UARTBAUD_BOTHEDGE;
- tmp &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT);
- tmp |= ((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT;
+ baud &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT);
+ baud |= ((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT;
- tmp &= ~UARTBAUD_SBR_MASK;
- tmp |= sbr & UARTBAUD_SBR_MASK;
+ baud &= ~UARTBAUD_SBR_MASK;
+ baud |= sbr & UARTBAUD_SBR_MASK;
if (!use_rx_dma)
- tmp &= ~UARTBAUD_RDMAE;
+ baud &= ~UARTBAUD_RDMAE;
if (!use_tx_dma)
- tmp &= ~UARTBAUD_TDMAE;
+ baud &= ~UARTBAUD_TDMAE;
- lpuart32_write(port, tmp, UARTBAUD);
+ lpuart32_write(port, baud, UARTBAUD);
}
static void lpuart32_serial_setbrg(struct lpuart_port *sport,
@@ -2218,17 +2225,18 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
{
struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
unsigned long flags;
- unsigned long ctrl, old_ctrl, bd, modem;
+ u32 ctrl, old_ctrl, bd, modem;
unsigned int baud;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
- ctrl = old_ctrl = lpuart32_read(&sport->port, UARTCTRL);
- bd = lpuart32_read(&sport->port, UARTBAUD);
- modem = lpuart32_read(&sport->port, UARTMODIR);
+ ctrl = old_ctrl = lpuart32_read(port, UARTCTRL);
+ bd = lpuart32_read(port, UARTBAUD);
+ modem = lpuart32_read(port, UARTMODIR);
sport->is_cs7 = false;
/*
- * only support CS8 and CS7, and for CS7 must enable PE.
+ * only support CS8 and CS7
* supported mode:
+ * - (7,n,1) (imx only)
* - (7,e/o,1)
* - (8,n,1)
* - (8,m/s,1)
@@ -2243,7 +2251,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
if ((termios->c_cflag & CSIZE) == CS8 ||
(termios->c_cflag & CSIZE) == CS7)
- ctrl = old_ctrl & ~UARTCTRL_M;
+ ctrl = old_ctrl & ~(UARTCTRL_M | UARTCTRL_M7);
if (termios->c_cflag & CMSPAR) {
if ((termios->c_cflag & CSIZE) != CS8) {
@@ -2257,7 +2265,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
* When auto RS-485 RTS mode is enabled,
* hardware flow control need to be disabled.
*/
- if (sport->port.rs485.flags & SER_RS485_ENABLED)
+ if (port->rs485.flags & SER_RS485_ENABLED)
termios->c_cflag &= ~CRTSCTS;
if (termios->c_cflag & CRTSCTS)
@@ -2270,9 +2278,18 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
else
bd &= ~UARTBAUD_SBNS;
- /* parity must be enabled when CS7 to match 8-bits format */
- if ((termios->c_cflag & CSIZE) == CS7)
- termios->c_cflag |= PARENB;
+ /*
+ * imx support 7-bits format, no limitation on parity when CS7
+ * for layerscape, parity must be enabled when CS7 to match 8-bits format
+ */
+ if ((termios->c_cflag & CSIZE) == CS7 && !(termios->c_cflag & PARENB)) {
+ if (is_imx7ulp_lpuart(sport) ||
+ is_imx8ulp_lpuart(sport) ||
+ is_imx8qxp_lpuart(sport))
+ ctrl |= UARTCTRL_M7;
+ else
+ termios->c_cflag |= PARENB;
+ }
if ((termios->c_cflag & PARENB)) {
if (termios->c_cflag & CMSPAR) {
@@ -2298,59 +2315,61 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
* Need to update the Ring buffer length according to the selected
* baud rate and restart Rx DMA path.
*
- * Since timer function acqures sport->port.lock, need to stop before
- * acquring same lock because otherwise del_timer_sync() can deadlock.
+ * Since timer function acqures port->lock, need to stop before
+ * acquring same lock because otherwise timer_delete_sync() can deadlock.
*/
if (old && sport->lpuart_dma_rx_use)
- lpuart_dma_rx_free(&sport->port);
+ lpuart_dma_rx_free(port);
- uart_port_lock_irqsave(&sport->port, &flags);
+ uart_port_lock_irqsave(port, &flags);
- sport->port.read_status_mask = 0;
+ port->read_status_mask = 0;
if (termios->c_iflag & INPCK)
- sport->port.read_status_mask |= UARTSTAT_FE | UARTSTAT_PE;
+ port->read_status_mask |= UARTSTAT_FE | UARTSTAT_PE;
if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
- sport->port.read_status_mask |= UARTSTAT_FE;
+ port->read_status_mask |= UARTSTAT_FE;
/* characters to ignore */
- sport->port.ignore_status_mask = 0;
+ port->ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
- sport->port.ignore_status_mask |= UARTSTAT_PE;
+ port->ignore_status_mask |= UARTSTAT_PE;
if (termios->c_iflag & IGNBRK) {
- sport->port.ignore_status_mask |= UARTSTAT_FE;
+ port->ignore_status_mask |= UARTSTAT_FE;
/*
* if we're ignoring parity and break indicators,
* ignore overruns too (for real raw support).
*/
if (termios->c_iflag & IGNPAR)
- sport->port.ignore_status_mask |= UARTSTAT_OR;
+ port->ignore_status_mask |= UARTSTAT_OR;
}
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
/*
+ * disable CTS to ensure the transmit engine is not blocked by the flow
+ * control when there is dirty data in TX FIFO
+ */
+ lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR);
+
+ /*
* LPUART Transmission Complete Flag may never be set while queuing a break
* character, so skip waiting for transmission complete when UARTCTRL_SBK is
* asserted.
*/
- if (!(old_ctrl & UARTCTRL_SBK)) {
- lpuart32_write(&sport->port, 0, UARTMODIR);
- lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC);
- }
+ if (!(old_ctrl & UARTCTRL_SBK))
+ lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TC);
/* disable transmit and receive */
- lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
+ lpuart32_write(port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE),
UARTCTRL);
- lpuart32_write(&sport->port, bd, UARTBAUD);
+ lpuart32_write(port, bd, UARTBAUD);
lpuart32_serial_setbrg(sport, baud);
- /* disable CTS before enabling UARTCTRL_TE to avoid pending idle preamble */
- lpuart32_write(&sport->port, modem & ~UARTMODIR_TXCTSE, UARTMODIR);
/* restore control register */
- lpuart32_write(&sport->port, ctrl, UARTCTRL);
+ lpuart32_write(port, ctrl, UARTCTRL);
/* re-enable the CTS if needed */
- lpuart32_write(&sport->port, modem, UARTMODIR);
+ lpuart32_write(port, modem, UARTMODIR);
if ((ctrl & (UARTCTRL_PE | UARTCTRL_M)) == UARTCTRL_PE)
sport->is_cs7 = true;
@@ -2362,7 +2381,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
sport->lpuart_dma_rx_use = false;
}
- uart_port_unlock_irqrestore(&sport->port, flags);
+ uart_port_unlock_irqrestore(port, flags);
}
static const char *lpuart_type(struct uart_port *port)
@@ -2475,7 +2494,7 @@ static void
lpuart_console_write(struct console *co, const char *s, unsigned int count)
{
struct lpuart_port *sport = lpuart_ports[co->index];
- unsigned char old_cr2, cr2;
+ u8 old_cr2, cr2;
unsigned long flags;
int locked = 1;
@@ -2505,7 +2524,7 @@ static void
lpuart32_console_write(struct console *co, const char *s, unsigned int count)
{
struct lpuart_port *sport = lpuart_ports[co->index];
- unsigned long old_cr, cr;
+ u32 old_cr, cr;
unsigned long flags;
int locked = 1;
@@ -2539,7 +2558,7 @@ static void __init
lpuart_console_get_options(struct lpuart_port *sport, int *baud,
int *parity, int *bits)
{
- unsigned char cr, bdh, bdl, brfa;
+ u8 cr, bdh, bdl, brfa;
unsigned int sbr, uartclk, baud_raw;
cr = readb(sport->port.membase + UARTCR2);
@@ -2588,7 +2607,7 @@ static void __init
lpuart32_console_get_options(struct lpuart_port *sport, int *baud,
int *parity, int *bits)
{
- unsigned long cr, bd;
+ u32 cr, bd;
unsigned int sbr, uartclk, baud_raw;
cr = lpuart32_read(&sport->port, UARTCTRL);
@@ -2794,13 +2813,13 @@ static int lpuart_global_reset(struct lpuart_port *sport)
{
struct uart_port *port = &sport->port;
void __iomem *global_addr;
- unsigned long ctrl, bd;
+ u32 ctrl, bd;
unsigned int val = 0;
int ret;
ret = clk_prepare_enable(sport->ipg_clk);
if (ret) {
- dev_err(sport->port.dev, "failed to enable uart ipg clk: %d\n", ret);
+ dev_err(port->dev, "failed to enable uart ipg clk: %d\n", ret);
return ret;
}
@@ -2811,10 +2830,10 @@ static int lpuart_global_reset(struct lpuart_port *sport)
*/
ctrl = lpuart32_read(port, UARTCTRL);
if (ctrl & UARTCTRL_TE) {
- bd = lpuart32_read(&sport->port, UARTBAUD);
+ bd = lpuart32_read(port, UARTBAUD);
if (read_poll_timeout(lpuart32_tx_empty, val, val, 1, 100000, false,
port)) {
- dev_warn(sport->port.dev,
+ dev_warn(port->dev,
"timeout waiting for transmit engine to complete\n");
clk_disable_unprepare(sport->ipg_clk);
return 0;
@@ -2884,8 +2903,7 @@ static int lpuart_probe(struct platform_device *pdev)
sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(sport->ipg_clk)) {
ret = PTR_ERR(sport->ipg_clk);
- dev_err(&pdev->dev, "failed to get uart ipg clk: %d\n", ret);
- return ret;
+ return dev_err_probe(&pdev->dev, ret, "failed to get uart ipg clk\n");
}
sport->baud_clk = NULL;
@@ -2893,8 +2911,7 @@ static int lpuart_probe(struct platform_device *pdev)
sport->baud_clk = devm_clk_get(&pdev->dev, "baud");
if (IS_ERR(sport->baud_clk)) {
ret = PTR_ERR(sport->baud_clk);
- dev_err(&pdev->dev, "failed to get uart baud clk: %d\n", ret);
- return ret;
+ return dev_err_probe(&pdev->dev, ret, "failed to get uart baud clk\n");
}
}
@@ -2930,6 +2947,7 @@ static int lpuart_probe(struct platform_device *pdev)
pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
+ pm_runtime_mark_last_busy(&pdev->dev);
ret = lpuart_global_reset(sport);
if (ret)
@@ -2944,7 +2962,7 @@ static int lpuart_probe(struct platform_device *pdev)
goto failed_attach_port;
ret = devm_request_irq(&pdev->dev, sport->port.irq, handler, 0,
- DRIVER_NAME, sport);
+ dev_name(&pdev->dev), sport);
if (ret)
goto failed_irq_request;
@@ -3001,7 +3019,7 @@ static int lpuart_runtime_resume(struct device *dev)
static void serial_lpuart_enable_wakeup(struct lpuart_port *sport, bool on)
{
- unsigned int val, baud;
+ u32 val, baud;
if (lpuart_is_32(sport)) {
val = lpuart32_read(&sport->port, UARTCTRL);
@@ -3066,7 +3084,7 @@ static int lpuart_suspend_noirq(struct device *dev)
static int lpuart_resume_noirq(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
- unsigned int val;
+ u32 stat;
pinctrl_pm_select_default_state(dev);
@@ -3075,8 +3093,8 @@ static int lpuart_resume_noirq(struct device *dev)
/* clear the wakeup flags */
if (lpuart_is_32(sport)) {
- val = lpuart32_read(&sport->port, UARTSTAT);
- lpuart32_write(&sport->port, val, UARTSTAT);
+ stat = lpuart32_read(&sport->port, UARTSTAT);
+ lpuart32_write(&sport->port, stat, UARTSTAT);
}
}
@@ -3086,7 +3104,8 @@ static int lpuart_resume_noirq(struct device *dev)
static int lpuart_suspend(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
- unsigned long temp, flags;
+ u32 temp;
+ unsigned long flags;
uart_suspend_port(&lpuart_reg, &sport->port);
@@ -3166,7 +3185,7 @@ static void lpuart_console_fixup(struct lpuart_port *sport)
* in VLLS mode, or restore console setting here.
*/
if (is_imx7ulp_lpuart(sport) && lpuart_uport_is_active(sport) &&
- console_suspend_enabled && uart_console(&sport->port)) {
+ console_suspend_enabled && uart_console(uport)) {
mutex_lock(&port->mutex);
memset(&termios, 0, sizeof(struct ktermios));
@@ -3212,7 +3231,7 @@ static const struct dev_pm_ops lpuart_pm_ops = {
static struct platform_driver lpuart_driver = {
.probe = lpuart_probe,
- .remove_new = lpuart_remove,
+ .remove = lpuart_remove,
.driver = {
.name = "fsl-lpuart",
.of_match_table = lpuart_dt_ids,
diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c
index a75eafbcbea3..7fb995a8490e 100644
--- a/drivers/tty/serial/icom.c
+++ b/drivers/tty/serial/icom.c
@@ -877,10 +877,10 @@ unlock:
static int icom_write(struct uart_port *port)
{
struct icom_port *icom_port = to_icom_port(port);
+ struct tty_port *tport = &port->state->port;
unsigned long data_count;
unsigned char cmdReg;
unsigned long offset;
- int temp_tail = port->state->xmit.tail;
trace(icom_port, "WRITE", 0);
@@ -890,16 +890,8 @@ static int icom_write(struct uart_port *port)
return 0;
}
- data_count = 0;
- while ((port->state->xmit.head != temp_tail) &&
- (data_count <= XMIT_BUFF_SZ)) {
-
- icom_port->xmit_buf[data_count++] =
- port->state->xmit.buf[temp_tail];
-
- temp_tail++;
- temp_tail &= (UART_XMIT_SIZE - 1);
- }
+ data_count = kfifo_out_peek(&tport->xmit_fifo, icom_port->xmit_buf,
+ XMIT_BUFF_SZ);
if (data_count) {
icom_port->statStg->xmit[0].flags =
@@ -956,7 +948,8 @@ static inline void check_modem_status(struct icom_port *icom_port)
static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
{
- u16 count, i;
+ struct tty_port *tport = &icom_port->uart_port.state->port;
+ u16 count;
if (port_int_reg & (INT_XMIT_COMPLETED)) {
trace(icom_port, "XMIT_COMPLETE", 0);
@@ -968,13 +961,7 @@ static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
count = le16_to_cpu(icom_port->statStg->xmit[0].leLength);
icom_port->uart_port.icount.tx += count;
- for (i=0; i<count &&
- !uart_circ_empty(&icom_port->uart_port.state->xmit); i++) {
-
- icom_port->uart_port.state->xmit.tail++;
- icom_port->uart_port.state->xmit.tail &=
- (UART_XMIT_SIZE - 1);
- }
+ kfifo_skip_count(&tport->xmit_fifo, count);
if (!icom_write(&icom_port->uart_port))
/* activate write queue */
@@ -1777,11 +1764,10 @@ static int icom_probe(struct pci_dev *dev,
goto probe_exit1;
}
- /* save off irq and request irq line */
- retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter);
- if (retval) {
- goto probe_exit2;
- }
+ /* save off irq and request irq line */
+ retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, icom_adapter);
+ if (retval)
+ goto probe_exit2;
retval = icom_load_ports(icom_adapter);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index e14813250616..e4b6f1bfdc95 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -8,6 +8,7 @@
* Copyright (C) 2004 Pengutronix
*/
+#include <linux/circ_buf.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
@@ -26,6 +27,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/dma-mapping.h>
#include <asm/irq.h>
@@ -118,6 +120,7 @@
#define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */
#define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */
#define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */
+#define UFCR_RXTL_MASK 0x3F /* Receiver trigger 6 bits wide */
#define UFCR_DCEDTE (1<<6) /* DCE/DTE mode select */
#define UFCR_RFDIV (7<<7) /* Reference freq divider mask */
#define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7)
@@ -227,6 +230,8 @@ struct imx_port {
unsigned int saved_reg[10];
bool context_saved;
+ bool last_putchar_was_newline;
+
enum imx_tx_state tx_state;
struct hrtimer trigger_start_tx;
struct hrtimer trigger_stop_tx;
@@ -262,6 +267,11 @@ static const struct of_device_id imx_uart_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, imx_uart_dt_ids);
+static inline struct imx_port *to_imx_port(struct uart_port *port)
+{
+ return container_of(port, struct imx_port, port);
+}
+
static inline void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset)
{
writel(val, sport->port.membase + offset);
@@ -362,6 +372,7 @@ static void imx_uart_soft_reset(struct imx_port *sport)
sport->idle_counter = 0;
}
+/* called with port.lock taken and irqs off */
static void imx_uart_disable_loopback_rs485(struct imx_port *sport)
{
unsigned int uts;
@@ -375,7 +386,7 @@ static void imx_uart_disable_loopback_rs485(struct imx_port *sport)
/* called with port.lock taken and irqs off */
static void imx_uart_start_rx(struct uart_port *port)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
unsigned int ucr1, ucr2;
ucr1 = imx_uart_readl(sport, UCR1);
@@ -399,7 +410,7 @@ static void imx_uart_start_rx(struct uart_port *port)
/* called with port.lock taken and irqs off */
static void imx_uart_stop_tx(struct uart_port *port)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
u32 ucr1, ucr4, usr2;
if (sport->tx_state == OFF)
@@ -462,9 +473,10 @@ static void imx_uart_stop_tx(struct uart_port *port)
}
}
+/* called with port.lock taken and irqs off */
static void imx_uart_stop_rx_with_loopback_ctrl(struct uart_port *port, bool loopback)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
u32 ucr1, ucr2, ucr4, uts;
ucr1 = imx_uart_readl(sport, UCR1);
@@ -509,7 +521,7 @@ static void imx_uart_stop_rx(struct uart_port *port)
/* called with port.lock taken and irqs off */
static void imx_uart_enable_ms(struct uart_port *port)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
mod_timer(&sport->timer, jiffies);
@@ -521,7 +533,8 @@ static void imx_uart_dma_tx(struct imx_port *sport);
/* called with port.lock taken and irqs off */
static inline void imx_uart_transmit_buffer(struct imx_port *sport)
{
- struct circ_buf *xmit = &sport->port.state->xmit;
+ struct tty_port *tport = &sport->port.state->port;
+ unsigned char c;
if (sport->port.x_char) {
/* Send next char */
@@ -531,7 +544,8 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport)
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) ||
+ uart_tx_stopped(&sport->port)) {
imx_uart_stop_tx(&sport->port);
return;
}
@@ -555,26 +569,22 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport)
return;
}
- while (!uart_circ_empty(xmit) &&
- !(imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL)) {
- /* send xmit->buf[xmit->tail]
- * out the port here */
- imx_uart_writel(sport, xmit->buf[xmit->tail], URTX0);
- uart_xmit_advance(&sport->port, 1);
- }
+ while (!(imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL) &&
+ uart_fifo_get(&sport->port, &c))
+ imx_uart_writel(sport, c, URTX0);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
imx_uart_stop_tx(&sport->port);
}
static void imx_uart_dma_tx_callback(void *data)
{
struct imx_port *sport = data;
+ struct tty_port *tport = &sport->port.state->port;
struct scatterlist *sgl = &sport->tx_sgl[0];
- struct circ_buf *xmit = &sport->port.state->xmit;
unsigned long flags;
u32 ucr1;
@@ -592,10 +602,11 @@ static void imx_uart_dma_tx_callback(void *data)
sport->dma_is_txing = 0;
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
- if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
+ if (!kfifo_is_empty(&tport->xmit_fifo) &&
+ !uart_tx_stopped(&sport->port))
imx_uart_dma_tx(sport);
else if (sport->port.rs485.flags & SER_RS485_ENABLED) {
u32 ucr4 = imx_uart_readl(sport, UCR4);
@@ -609,7 +620,7 @@ static void imx_uart_dma_tx_callback(void *data)
/* called with port.lock taken and irqs off */
static void imx_uart_dma_tx(struct imx_port *sport)
{
- struct circ_buf *xmit = &sport->port.state->xmit;
+ struct tty_port *tport = &sport->port.state->port;
struct scatterlist *sgl = sport->tx_sgl;
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = sport->dma_chan_tx;
@@ -624,18 +635,10 @@ static void imx_uart_dma_tx(struct imx_port *sport)
ucr4 &= ~UCR4_TCEN;
imx_uart_writel(sport, ucr4, UCR4);
- sport->tx_bytes = uart_circ_chars_pending(xmit);
-
- if (xmit->tail < xmit->head || xmit->head == 0) {
- sport->dma_tx_nents = 1;
- sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
- } else {
- sport->dma_tx_nents = 2;
- sg_init_table(sgl, 2);
- sg_set_buf(sgl, xmit->buf + xmit->tail,
- UART_XMIT_SIZE - xmit->tail);
- sg_set_buf(sgl + 1, xmit->buf, xmit->head);
- }
+ sg_init_table(sgl, ARRAY_SIZE(sport->tx_sgl));
+ sport->tx_bytes = kfifo_len(&tport->xmit_fifo);
+ sport->dma_tx_nents = kfifo_dma_out_prepare(&tport->xmit_fifo, sgl,
+ ARRAY_SIZE(sport->tx_sgl), sport->tx_bytes);
ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
if (ret == 0) {
@@ -653,8 +656,7 @@ static void imx_uart_dma_tx(struct imx_port *sport)
desc->callback = imx_uart_dma_tx_callback;
desc->callback_param = sport;
- dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
- uart_circ_chars_pending(xmit));
+ dev_dbg(dev, "TX: prepare to send %u bytes by DMA.\n", sport->tx_bytes);
ucr1 = imx_uart_readl(sport, UCR1);
ucr1 |= UCR1_TXDMAEN;
@@ -670,10 +672,11 @@ static void imx_uart_dma_tx(struct imx_port *sport)
/* called with port.lock taken and irqs off */
static void imx_uart_start_tx(struct uart_port *port)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
+ struct tty_port *tport = &sport->port.state->port;
u32 ucr1;
- if (!sport->port.x_char && uart_circ_empty(&port->state->xmit))
+ if (!sport->port.x_char && kfifo_is_empty(&tport->xmit_fifo))
return;
/*
@@ -749,7 +752,7 @@ static void imx_uart_start_tx(struct uart_port *port)
return;
}
- if (!uart_circ_empty(&port->state->xmit) &&
+ if (!kfifo_is_empty(&tport->xmit_fifo) &&
!uart_tx_stopped(port))
imx_uart_dma_tx(sport);
return;
@@ -763,6 +766,21 @@ static irqreturn_t __imx_uart_rtsint(int irq, void *dev_id)
imx_uart_writel(sport, USR1_RTSD, USR1);
usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS;
+ /*
+ * Update sport->old_status here, so any follow-up calls to
+ * imx_uart_mctrl_check() will be able to recognize that RTS
+ * state changed since last imx_uart_mctrl_check() call.
+ *
+ * In case RTS has been detected as asserted here and later on
+ * deasserted by the time imx_uart_mctrl_check() was called,
+ * imx_uart_mctrl_check() can detect the RTS state change and
+ * trigger uart_handle_cts_change() to unblock the port for
+ * further TX transfers.
+ */
+ if (usr1 & USR1_RTSS)
+ sport->old_status |= TIOCM_CTS;
+ else
+ sport->old_status &= ~TIOCM_CTS;
uart_handle_cts_change(&sport->port, usr1);
wake_up_interruptible(&sport->port.state->port.delta_msr_wait);
@@ -804,6 +822,8 @@ static irqreturn_t imx_uart_txint(int irq, void *dev_id)
* issuing soft reset to the UART (just stop/start of RX does not help). Note
* that what we do here is sending isolated start bit about 2.4 times shorter
* than it is to be on UART configured baud rate.
+ *
+ * Called with port.lock taken and irqs off.
*/
static void imx_uart_check_flood(struct imx_port *sport, u32 usr2)
{
@@ -839,6 +859,7 @@ static void imx_uart_check_flood(struct imx_port *sport, u32 usr2)
}
}
+/* called with port.lock taken and irqs off */
static irqreturn_t __imx_uart_rxint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
@@ -917,6 +938,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport);
/*
* We have a modem side uart, so the meanings of RTS and CTS are inverted.
*/
+/* called with port.lock taken and irqs off */
static unsigned int imx_uart_get_hwmctrl(struct imx_port *sport)
{
unsigned int tmp = TIOCM_DSR;
@@ -939,6 +961,8 @@ static unsigned int imx_uart_get_hwmctrl(struct imx_port *sport)
/*
* Handle any change of modem status signal since we were last called.
+ *
+ * Called with port.lock taken and irqs off.
*/
static void imx_uart_mctrl_check(struct imx_port *sport)
{
@@ -1050,7 +1074,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id)
*/
static unsigned int imx_uart_tx_empty(struct uart_port *port)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
unsigned int ret;
ret = (imx_uart_readl(sport, USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0;
@@ -1065,7 +1089,7 @@ static unsigned int imx_uart_tx_empty(struct uart_port *port)
/* called with port.lock taken and irqs off */
static unsigned int imx_uart_get_mctrl(struct uart_port *port)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
unsigned int ret = imx_uart_get_hwmctrl(sport);
mctrl_gpio_get(sport->gpios, &ret);
@@ -1076,7 +1100,7 @@ static unsigned int imx_uart_get_mctrl(struct uart_port *port)
/* called with port.lock taken and irqs off */
static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
u32 ucr3, uts;
if (!(port->rs485.flags & SER_RS485_ENABLED)) {
@@ -1119,7 +1143,7 @@ static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
*/
static void imx_uart_break_ctl(struct uart_port *port, int break_state)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
unsigned long flags;
u32 ucr1;
@@ -1278,6 +1302,7 @@ static int imx_uart_start_rx_dma(struct imx_port *sport)
return 0;
}
+/* called with port.lock taken and irqs off */
static void imx_uart_clear_rx_errors(struct imx_port *sport)
{
struct tty_port *port = &sport->port.state->port;
@@ -1312,7 +1337,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport)
}
-#define TXTL_DEFAULT 2 /* reset default */
+#define TXTL_DEFAULT 8
#define RXTL_DEFAULT 8 /* 8 characters or aging timer */
#define TXTL_DMA 8 /* DMA burst setting */
#define RXTL_DMA 9 /* DMA burst setting */
@@ -1408,6 +1433,7 @@ err:
return ret;
}
+/* called with port.lock taken and irqs off */
static void imx_uart_enable_dma(struct imx_port *sport)
{
u32 ucr1;
@@ -1441,7 +1467,7 @@ static void imx_uart_disable_dma(struct imx_port *sport)
static int imx_uart_startup(struct uart_port *port)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
int retval;
unsigned long flags;
int dma_is_inited = 0;
@@ -1555,9 +1581,10 @@ static int imx_uart_startup(struct uart_port *port)
static void imx_uart_shutdown(struct uart_port *port)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
unsigned long flags;
u32 ucr1, ucr2, ucr4, uts;
+ int loops;
if (sport->dma_is_enabled) {
dmaengine_terminate_sync(sport->dma_chan_tx);
@@ -1581,7 +1608,7 @@ static void imx_uart_shutdown(struct uart_port *port)
imx_uart_dma_exit(sport);
}
- mctrl_gpio_disable_ms(sport->gpios);
+ mctrl_gpio_disable_ms_sync(sport->gpios);
uart_port_lock_irqsave(&sport->port, &flags);
ucr2 = imx_uart_readl(sport, UCR2);
@@ -1592,7 +1619,7 @@ static void imx_uart_shutdown(struct uart_port *port)
/*
* Stop our timer.
*/
- del_timer_sync(&sport->timer);
+ timer_delete_sync(&sport->timer);
/*
* Disable all interrupts, port and break condition.
@@ -1620,6 +1647,56 @@ static void imx_uart_shutdown(struct uart_port *port)
ucr4 &= ~UCR4_TCEN;
imx_uart_writel(sport, ucr4, UCR4);
+ /*
+ * We have to ensure the tx state machine ends up in OFF. This
+ * is especially important for rs485 where we must not leave
+ * the RTS signal high, blocking the bus indefinitely.
+ *
+ * All interrupts are now disabled, so imx_uart_stop_tx() will
+ * no longer be called from imx_uart_transmit_buffer(). It may
+ * still be called via the hrtimers, and if those are in play,
+ * we have to honour the delays.
+ */
+ if (sport->tx_state == WAIT_AFTER_RTS || sport->tx_state == SEND)
+ imx_uart_stop_tx(port);
+
+ /*
+ * In many cases (rs232 mode, or if tx_state was
+ * WAIT_AFTER_RTS, or if tx_state was SEND and there is no
+ * delay_rts_after_send), this will have moved directly to
+ * OFF. In rs485 mode, tx_state might already have been
+ * WAIT_AFTER_SEND and the hrtimer thus already started, or
+ * the above imx_uart_stop_tx() call could have started it. In
+ * those cases, we have to wait for the hrtimer to fire and
+ * complete the transition to OFF.
+ */
+ loops = port->rs485.flags & SER_RS485_ENABLED ?
+ port->rs485.delay_rts_after_send : 0;
+ while (sport->tx_state != OFF && loops--) {
+ uart_port_unlock_irqrestore(&sport->port, flags);
+ msleep(1);
+ uart_port_lock_irqsave(&sport->port, &flags);
+ }
+
+ if (sport->tx_state != OFF) {
+ dev_warn(sport->port.dev, "unexpected tx_state %d\n",
+ sport->tx_state);
+ /*
+ * This machine may be busted, but ensure the RTS
+ * signal is inactive in order not to block other
+ * devices.
+ */
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ ucr2 = imx_uart_readl(sport, UCR2);
+ if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND)
+ imx_uart_rts_active(sport, &ucr2);
+ else
+ imx_uart_rts_inactive(sport, &ucr2);
+ imx_uart_writel(sport, ucr2, UCR2);
+ }
+ sport->tx_state = OFF;
+ }
+
uart_port_unlock_irqrestore(&sport->port, flags);
clk_disable_unprepare(sport->clk_per);
@@ -1629,7 +1706,7 @@ static void imx_uart_shutdown(struct uart_port *port)
/* called with port.lock taken and irqs off */
static void imx_uart_flush_buffer(struct uart_port *port)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
struct scatterlist *sgl = &sport->tx_sgl[0];
if (!sport->dma_chan_tx)
@@ -1656,7 +1733,7 @@ static void
imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
const struct ktermios *old)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
unsigned long flags;
u32 ucr2, old_ucr2, ufcr;
unsigned int baud, quot;
@@ -1675,7 +1752,7 @@ imx_uart_set_termios(struct uart_port *port, struct ktermios *termios,
old_csize = CS8;
}
- del_timer_sync(&sport->timer);
+ timer_delete_sync(&sport->timer);
/*
* Ask the core to calculate the divisor for us.
@@ -1859,7 +1936,7 @@ imx_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
static int imx_uart_poll_init(struct uart_port *port)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
unsigned long flags;
u32 ucr1, ucr2;
int retval;
@@ -1908,7 +1985,7 @@ static int imx_uart_poll_init(struct uart_port *port)
static int imx_uart_poll_get_char(struct uart_port *port)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
if (!(imx_uart_readl(sport, USR2) & USR2_RDR))
return NO_POLL_CHAR;
@@ -1917,7 +1994,7 @@ static int imx_uart_poll_get_char(struct uart_port *port)
static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
unsigned int status;
/* drain */
@@ -1939,8 +2016,8 @@ static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c)
static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termios,
struct serial_rs485 *rs485conf)
{
- struct imx_port *sport = (struct imx_port *)port;
- u32 ucr2;
+ struct imx_port *sport = to_imx_port(port);
+ u32 ucr2, ufcr;
if (rs485conf->flags & SER_RS485_ENABLED) {
/* Enable receiver if low-active RTS signal is requested */
@@ -1959,8 +2036,13 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio
/* Make sure Rx is enabled in case Tx is active with Rx disabled */
if (!(rs485conf->flags & SER_RS485_ENABLED) ||
- rs485conf->flags & SER_RS485_RX_DURING_TX)
+ rs485conf->flags & SER_RS485_RX_DURING_TX) {
+ /* If the receiver trigger is 0, set it to a default value */
+ ufcr = imx_uart_readl(sport, UFCR);
+ if ((ufcr & UFCR_RXTL_MASK) == 0)
+ imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT);
imx_uart_start_rx(port);
+ }
return 0;
}
@@ -1993,32 +2075,40 @@ static struct imx_port *imx_uart_ports[UART_NR];
#if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE)
static void imx_uart_console_putchar(struct uart_port *port, unsigned char ch)
{
- struct imx_port *sport = (struct imx_port *)port;
+ struct imx_port *sport = to_imx_port(port);
while (imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL)
barrier();
imx_uart_writel(sport, ch, URTX0);
+
+ sport->last_putchar_was_newline = (ch == '\n');
}
-/*
- * Interrupts are disabled on entering
- */
-static void
-imx_uart_console_write(struct console *co, const char *s, unsigned int count)
+static void imx_uart_console_device_lock(struct console *co, unsigned long *flags)
+{
+ struct uart_port *up = &imx_uart_ports[co->index]->port;
+
+ return __uart_port_lock_irqsave(up, flags);
+}
+
+static void imx_uart_console_device_unlock(struct console *co, unsigned long flags)
+{
+ struct uart_port *up = &imx_uart_ports[co->index]->port;
+
+ return __uart_port_unlock_irqrestore(up, flags);
+}
+
+static void imx_uart_console_write_atomic(struct console *co,
+ struct nbcon_write_context *wctxt)
{
struct imx_port *sport = imx_uart_ports[co->index];
+ struct uart_port *port = &sport->port;
struct imx_port_ucrs old_ucr;
- unsigned long flags;
- unsigned int ucr1;
- int locked = 1;
+ unsigned int ucr1, usr2;
- if (sport->port.sysrq)
- locked = 0;
- else if (oops_in_progress)
- locked = uart_port_trylock_irqsave(&sport->port, &flags);
- else
- uart_port_lock_irqsave(&sport->port, &flags);
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
/*
* First, save UCR1/2/3 and then disable interrupts
@@ -2032,21 +2122,88 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count)
ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN);
imx_uart_writel(sport, ucr1, UCR1);
-
imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2);
- uart_console_write(&sport->port, s, count, imx_uart_console_putchar);
+ if (!sport->last_putchar_was_newline)
+ uart_console_write(port, "\n", 1, imx_uart_console_putchar);
+ uart_console_write(port, wctxt->outbuf, wctxt->len,
+ imx_uart_console_putchar);
/*
* Finally, wait for transmitter to become empty
* and restore UCR1/2/3
*/
- while (!(imx_uart_readl(sport, USR2) & USR2_TXDC));
+ read_poll_timeout_atomic(imx_uart_readl, usr2, usr2 & USR2_TXDC,
+ 0, USEC_PER_SEC, false, sport, USR2);
+ imx_uart_ucrs_restore(sport, &old_ucr);
+
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void imx_uart_console_write_thread(struct console *co,
+ struct nbcon_write_context *wctxt)
+{
+ struct imx_port *sport = imx_uart_ports[co->index];
+ struct uart_port *port = &sport->port;
+ struct imx_port_ucrs old_ucr;
+ unsigned int ucr1, usr2;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ /*
+ * First, save UCR1/2/3 and then disable interrupts
+ */
+ imx_uart_ucrs_save(sport, &old_ucr);
+ ucr1 = old_ucr.ucr1;
+ if (imx_uart_is_imx1(sport))
+ ucr1 |= IMX1_UCR1_UARTCLKEN;
+ ucr1 |= UCR1_UARTEN;
+ ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN);
+
+ imx_uart_writel(sport, ucr1, UCR1);
+ imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2);
+
+ if (nbcon_exit_unsafe(wctxt)) {
+ int len = READ_ONCE(wctxt->len);
+ int i;
+
+ /*
+ * Write out the message. Toggle unsafe for each byte in order
+ * to give another (higher priority) context the opportunity
+ * for a friendly takeover. If such a takeover occurs, this
+ * context must reacquire ownership in order to perform final
+ * actions (such as re-enabling the interrupts).
+ *
+ * IMPORTANT: wctxt->outbuf and wctxt->len are no longer valid
+ * after a reacquire so writing the message must be
+ * aborted.
+ */
+ for (i = 0; i < len; i++) {
+ if (!nbcon_enter_unsafe(wctxt))
+ break;
+
+ uart_console_write(port, wctxt->outbuf + i, 1,
+ imx_uart_console_putchar);
+
+ if (!nbcon_exit_unsafe(wctxt))
+ break;
+ }
+ }
+
+ while (!nbcon_enter_unsafe(wctxt))
+ nbcon_reacquire_nobuf(wctxt);
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore UCR1/2/3
+ */
+ read_poll_timeout(imx_uart_readl, usr2, usr2 & USR2_TXDC,
+ 0, USEC_PER_SEC, false, sport, USR2);
imx_uart_ucrs_restore(sport, &old_ucr);
- if (locked)
- uart_port_unlock_irqrestore(&sport->port, flags);
+ nbcon_exit_unsafe(wctxt);
}
/*
@@ -2138,6 +2295,8 @@ imx_uart_console_setup(struct console *co, char *options)
if (retval)
goto error_console;
+ sport->last_putchar_was_newline = true;
+
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
@@ -2174,11 +2333,14 @@ imx_uart_console_exit(struct console *co)
static struct uart_driver imx_uart_uart_driver;
static struct console imx_uart_console = {
.name = DEV_NAME,
- .write = imx_uart_console_write,
+ .write_atomic = imx_uart_console_write_atomic,
+ .write_thread = imx_uart_console_write_thread,
+ .device_lock = imx_uart_console_device_lock,
+ .device_unlock = imx_uart_console_device_unlock,
+ .flags = CON_PRINTBUFFER | CON_NBCON,
.device = uart_console_device,
.setup = imx_uart_console_setup,
.exit = imx_uart_console_exit,
- .flags = CON_PRINTBUFFER,
.index = -1,
.data = &imx_uart_uart_driver,
};
@@ -2420,10 +2582,10 @@ static int imx_uart_probe(struct platform_device *pdev)
imx_uart_writel(sport, ucr3, UCR3);
}
- hrtimer_init(&sport->trigger_start_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- hrtimer_init(&sport->trigger_stop_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- sport->trigger_start_tx.function = imx_trigger_start_tx;
- sport->trigger_stop_tx.function = imx_trigger_stop_tx;
+ hrtimer_setup(&sport->trigger_start_tx, imx_trigger_start_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ hrtimer_setup(&sport->trigger_stop_tx, imx_trigger_stop_tx, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
/*
* Allocate the IRQ(s) i.MX1 has three interrupts whereas later
@@ -2525,10 +2687,13 @@ static void imx_uart_save_context(struct imx_port *sport)
uart_port_unlock_irqrestore(&sport->port, flags);
}
+/* called with irq off */
static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
{
u32 ucr3;
+ uart_port_lock_irq(&sport->port);
+
ucr3 = imx_uart_readl(sport, UCR3);
if (on) {
imx_uart_writel(sport, USR1_AWAKE, USR1);
@@ -2548,6 +2713,8 @@ static void imx_uart_enable_wakeup(struct imx_port *sport, bool on)
}
imx_uart_writel(sport, ucr1, UCR1);
}
+
+ uart_port_unlock_irq(&sport->port);
}
static int imx_uart_suspend_noirq(struct device *dev)
@@ -2647,7 +2814,7 @@ static const struct dev_pm_ops imx_uart_pm_ops = {
static struct platform_driver imx_uart_platform_driver = {
.probe = imx_uart_probe,
- .remove_new = imx_uart_remove,
+ .remove = imx_uart_remove,
.driver = {
.name = "imx-uart",
diff --git a/drivers/tty/serial/ip22zilog.c b/drivers/tty/serial/ip22zilog.c
index 320b29cd4683..c2cae50f06f3 100644
--- a/drivers/tty/serial/ip22zilog.c
+++ b/drivers/tty/serial/ip22zilog.c
@@ -355,7 +355,8 @@ static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
struct zilog_channel *channel)
{
- struct circ_buf *xmit;
+ struct tty_port *tport;
+ unsigned char c;
if (ZS_IS_CONS(up)) {
unsigned char status = readb(&channel->control);
@@ -398,20 +399,18 @@ static void ip22zilog_transmit_chars(struct uart_ip22zilog_port *up,
if (up->port.state == NULL)
goto ack_tx_int;
- xmit = &up->port.state->xmit;
- if (uart_circ_empty(xmit))
- goto ack_tx_int;
+ tport = &up->port.state->port;
if (uart_tx_stopped(&up->port))
goto ack_tx_int;
+ if (!uart_fifo_get(&up->port, &c))
+ goto ack_tx_int;
up->flags |= IP22ZILOG_FLAG_TX_ACTIVE;
- writeb(xmit->buf[xmit->tail], &channel->data);
+ writeb(c, &channel->data);
ZSDELAY();
ZS_WSYNC(channel);
- uart_xmit_advance(&up->port, 1);
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
return;
@@ -600,17 +599,16 @@ static void ip22zilog_start_tx(struct uart_port *port)
port->icount.tx++;
port->x_char = 0;
} else {
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
+ unsigned char c;
- if (uart_circ_empty(xmit))
+ if (!uart_fifo_get(port, &c))
return;
- writeb(xmit->buf[xmit->tail], &channel->data);
+ writeb(c, &channel->data);
ZSDELAY();
ZS_WSYNC(channel);
- uart_xmit_advance(port, 1);
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
}
}
diff --git a/drivers/tty/serial/jsm/jsm_cls.c b/drivers/tty/serial/jsm/jsm_cls.c
index ddbd42c09637..6e40792f92cf 100644
--- a/drivers/tty/serial/jsm/jsm_cls.c
+++ b/drivers/tty/serial/jsm/jsm_cls.c
@@ -443,20 +443,14 @@ static void cls_copy_data_from_uart_to_queue(struct jsm_channel *ch)
static void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch)
{
- u16 tail;
+ struct tty_port *tport;
int n;
- int qlen;
u32 len_written = 0;
- struct circ_buf *circ;
if (!ch)
return;
- circ = &ch->uart_port.state->xmit;
-
- /* No data to write to the UART */
- if (uart_circ_empty(circ))
- return;
+ tport = &ch->uart_port.state->port;
/* If port is "stopped", don't send any data to the UART */
if ((ch->ch_flags & CH_STOP) || (ch->ch_flags & CH_BREAK_SENDING))
@@ -467,29 +461,22 @@ static void cls_copy_data_from_queue_to_uart(struct jsm_channel *ch)
return;
n = 32;
+ while (n > 0) {
+ unsigned char c;
- /* cache tail of queue */
- tail = circ->tail & (UART_XMIT_SIZE - 1);
- qlen = uart_circ_chars_pending(circ);
-
- /* Find minimum of the FIFO space, versus queue length */
- n = min(n, qlen);
+ if (!kfifo_get(&tport->xmit_fifo, &c))
+ break;
- while (n > 0) {
- writeb(circ->buf[tail], &ch->ch_cls_uart->txrx);
- tail = (tail + 1) & (UART_XMIT_SIZE - 1);
+ writeb(c, &ch->ch_cls_uart->txrx);
n--;
ch->ch_txcount++;
len_written++;
}
- /* Update the final tail */
- circ->tail = tail & (UART_XMIT_SIZE - 1);
-
if (len_written > ch->ch_t_tlevel)
ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
- if (uart_circ_empty(circ))
+ if (kfifo_is_empty(&tport->xmit_fifo))
uart_write_wakeup(&ch->uart_port);
}
diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c
index 1fa10f19368f..e8e13bf056e2 100644
--- a/drivers/tty/serial/jsm/jsm_neo.c
+++ b/drivers/tty/serial/jsm/jsm_neo.c
@@ -474,21 +474,21 @@ static void neo_copy_data_from_uart_to_queue(struct jsm_channel *ch)
static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
{
- u16 head;
- u16 tail;
+ struct tty_port *tport;
+ unsigned char *tail;
+ unsigned char c;
int n;
int s;
int qlen;
u32 len_written = 0;
- struct circ_buf *circ;
if (!ch)
return;
- circ = &ch->uart_port.state->xmit;
+ tport = &ch->uart_port.state->port;
/* No data to write to the UART */
- if (uart_circ_empty(circ))
+ if (kfifo_is_empty(&tport->xmit_fifo))
return;
/* If port is "stopped", don't send any data to the UART */
@@ -504,10 +504,9 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
if (ch->ch_cached_lsr & UART_LSR_THRE) {
ch->ch_cached_lsr &= ~(UART_LSR_THRE);
- writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx);
- jsm_dbg(WRITE, &ch->ch_bd->pci_dev,
- "Tx data: %x\n", circ->buf[circ->tail]);
- circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1);
+ WARN_ON_ONCE(!kfifo_get(&tport->xmit_fifo, &c));
+ writeb(c, &ch->ch_neo_uart->txrx);
+ jsm_dbg(WRITE, &ch->ch_bd->pci_dev, "Tx data: %x\n", c);
ch->ch_txcount++;
}
return;
@@ -520,38 +519,27 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch)
return;
n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel;
-
- /* cache head and tail of queue */
- head = circ->head & (UART_XMIT_SIZE - 1);
- tail = circ->tail & (UART_XMIT_SIZE - 1);
- qlen = uart_circ_chars_pending(circ);
+ qlen = kfifo_len(&tport->xmit_fifo);
/* Find minimum of the FIFO space, versus queue length */
n = min(n, qlen);
while (n > 0) {
-
- s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
- s = min(s, n);
-
+ s = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, n);
if (s <= 0)
break;
- memcpy_toio(&ch->ch_neo_uart->txrxburst, circ->buf + tail, s);
- /* Add and flip queue if needed */
- tail = (tail + s) & (UART_XMIT_SIZE - 1);
+ memcpy_toio(&ch->ch_neo_uart->txrxburst, tail, s);
+ kfifo_skip_count(&tport->xmit_fifo, s);
n -= s;
ch->ch_txcount += s;
len_written += s;
}
- /* Update the final tail */
- circ->tail = tail & (UART_XMIT_SIZE - 1);
-
if (len_written >= ch->ch_t_tlevel)
ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM);
- if (uart_circ_empty(circ))
+ if (kfifo_is_empty(&tport->xmit_fifo))
uart_write_wakeup(&ch->uart_port);
}
diff --git a/drivers/tty/serial/kgdb_nmi.c b/drivers/tty/serial/kgdb_nmi.c
deleted file mode 100644
index e93850f6447a..000000000000
--- a/drivers/tty/serial/kgdb_nmi.c
+++ /dev/null
@@ -1,381 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * KGDB NMI serial console
- *
- * Copyright 2010 Google, Inc.
- * Arve Hjønnevåg <arve@android.com>
- * Colin Cross <ccross@android.com>
- * Copyright 2012 Linaro Ltd.
- * Anton Vorontsov <anton.vorontsov@linaro.org>
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/compiler.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/atomic.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/interrupt.h>
-#include <linux/hrtimer.h>
-#include <linux/tick.h>
-#include <linux/kfifo.h>
-#include <linux/kgdb.h>
-#include <linux/kdb.h>
-
-static int kgdb_nmi_knock = 1;
-module_param_named(knock, kgdb_nmi_knock, int, 0600);
-MODULE_PARM_DESC(knock, "if set to 1 (default), the special '$3#33' command " \
- "must be used to enter the debugger; when set to 0, " \
- "hitting return key is enough to enter the debugger; " \
- "when set to -1, the debugger is entered immediately " \
- "upon NMI");
-
-static char *kgdb_nmi_magic = "$3#33";
-module_param_named(magic, kgdb_nmi_magic, charp, 0600);
-MODULE_PARM_DESC(magic, "magic sequence to enter NMI debugger (default $3#33)");
-
-static atomic_t kgdb_nmi_num_readers = ATOMIC_INIT(0);
-
-static int kgdb_nmi_console_setup(struct console *co, char *options)
-{
- arch_kgdb_ops.enable_nmi(1);
-
- /* The NMI console uses the dbg_io_ops to issue console messages. To
- * avoid duplicate messages during kdb sessions we must inform kdb's
- * I/O utilities that messages sent to the console will automatically
- * be displayed on the dbg_io.
- */
- dbg_io_ops->cons = co;
-
- return 0;
-}
-
-static void kgdb_nmi_console_write(struct console *co, const char *s, uint c)
-{
- int i;
-
- for (i = 0; i < c; i++)
- dbg_io_ops->write_char(s[i]);
-}
-
-static struct tty_driver *kgdb_nmi_tty_driver;
-
-static struct tty_driver *kgdb_nmi_console_device(struct console *co, int *idx)
-{
- *idx = co->index;
- return kgdb_nmi_tty_driver;
-}
-
-static struct console kgdb_nmi_console = {
- .name = "ttyNMI",
- .setup = kgdb_nmi_console_setup,
- .write = kgdb_nmi_console_write,
- .device = kgdb_nmi_console_device,
- .flags = CON_PRINTBUFFER | CON_ANYTIME,
- .index = -1,
-};
-
-/*
- * This is usually the maximum rate on debug ports. We make fifo large enough
- * to make copy-pasting to the terminal usable.
- */
-#define KGDB_NMI_BAUD 115200
-#define KGDB_NMI_FIFO_SIZE roundup_pow_of_two(KGDB_NMI_BAUD / 8 / HZ)
-
-struct kgdb_nmi_tty_priv {
- struct tty_port port;
- struct timer_list timer;
- STRUCT_KFIFO(char, KGDB_NMI_FIFO_SIZE) fifo;
-};
-
-static struct tty_port *kgdb_nmi_port;
-
-static void kgdb_tty_recv(int ch)
-{
- struct kgdb_nmi_tty_priv *priv;
- char c = ch;
-
- if (!kgdb_nmi_port || ch < 0)
- return;
- /*
- * Can't use port->tty->driver_data as tty might be not there. Timer
- * will check for tty and will get the ref, but here we don't have to
- * do that, and actually, we can't: we're in NMI context, no locks are
- * possible.
- */
- priv = container_of(kgdb_nmi_port, struct kgdb_nmi_tty_priv, port);
- kfifo_in(&priv->fifo, &c, 1);
-}
-
-static int kgdb_nmi_poll_one_knock(void)
-{
- static int n;
- int c;
- const char *magic = kgdb_nmi_magic;
- size_t m = strlen(magic);
- bool printch = false;
-
- c = dbg_io_ops->read_char();
- if (c == NO_POLL_CHAR)
- return c;
-
- if (!kgdb_nmi_knock && (c == '\r' || c == '\n')) {
- return 1;
- } else if (c == magic[n]) {
- n = (n + 1) % m;
- if (!n)
- return 1;
- printch = true;
- } else {
- n = 0;
- }
-
- if (atomic_read(&kgdb_nmi_num_readers)) {
- kgdb_tty_recv(c);
- return 0;
- }
-
- if (printch) {
- kdb_printf("%c", c);
- return 0;
- }
-
- kdb_printf("\r%s %s to enter the debugger> %*s",
- kgdb_nmi_knock ? "Type" : "Hit",
- kgdb_nmi_knock ? magic : "<return>", (int)m, "");
- while (m--)
- kdb_printf("\b");
- return 0;
-}
-
-/**
- * kgdb_nmi_poll_knock - Check if it is time to enter the debugger
- *
- * "Serial ports are often noisy, especially when muxed over another port (we
- * often use serial over the headset connector). Noise on the async command
- * line just causes characters that are ignored, on a command line that blocked
- * execution noise would be catastrophic." -- Colin Cross
- *
- * So, this function implements KGDB/KDB knocking on the serial line: we won't
- * enter the debugger until we receive a known magic phrase (which is actually
- * "$3#33", known as "escape to KDB" command. There is also a relaxed variant
- * of knocking, i.e. just pressing the return key is enough to enter the
- * debugger. And if knocking is disabled, the function always returns 1.
- */
-bool kgdb_nmi_poll_knock(void)
-{
- if (kgdb_nmi_knock < 0)
- return true;
-
- while (1) {
- int ret;
-
- ret = kgdb_nmi_poll_one_knock();
- if (ret == NO_POLL_CHAR)
- return false;
- else if (ret == 1)
- break;
- }
- return true;
-}
-
-/*
- * The tasklet is cheap, it does not cause wakeups when reschedules itself,
- * instead it waits for the next tick.
- */
-static void kgdb_nmi_tty_receiver(struct timer_list *t)
-{
- struct kgdb_nmi_tty_priv *priv = from_timer(priv, t, timer);
- char ch;
-
- priv->timer.expires = jiffies + (HZ/100);
- add_timer(&priv->timer);
-
- if (likely(!atomic_read(&kgdb_nmi_num_readers) ||
- !kfifo_len(&priv->fifo)))
- return;
-
- while (kfifo_out(&priv->fifo, &ch, 1))
- tty_insert_flip_char(&priv->port, ch, TTY_NORMAL);
- tty_flip_buffer_push(&priv->port);
-}
-
-static int kgdb_nmi_tty_activate(struct tty_port *port, struct tty_struct *tty)
-{
- struct kgdb_nmi_tty_priv *priv =
- container_of(port, struct kgdb_nmi_tty_priv, port);
-
- kgdb_nmi_port = port;
- priv->timer.expires = jiffies + (HZ/100);
- add_timer(&priv->timer);
-
- return 0;
-}
-
-static void kgdb_nmi_tty_shutdown(struct tty_port *port)
-{
- struct kgdb_nmi_tty_priv *priv =
- container_of(port, struct kgdb_nmi_tty_priv, port);
-
- del_timer(&priv->timer);
- kgdb_nmi_port = NULL;
-}
-
-static const struct tty_port_operations kgdb_nmi_tty_port_ops = {
- .activate = kgdb_nmi_tty_activate,
- .shutdown = kgdb_nmi_tty_shutdown,
-};
-
-static int kgdb_nmi_tty_install(struct tty_driver *drv, struct tty_struct *tty)
-{
- struct kgdb_nmi_tty_priv *priv;
- int ret;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- INIT_KFIFO(priv->fifo);
- timer_setup(&priv->timer, kgdb_nmi_tty_receiver, 0);
- tty_port_init(&priv->port);
- priv->port.ops = &kgdb_nmi_tty_port_ops;
- tty->driver_data = priv;
-
- ret = tty_port_install(&priv->port, drv, tty);
- if (ret) {
- pr_err("%s: can't install tty port: %d\n", __func__, ret);
- goto err;
- }
- return 0;
-err:
- tty_port_destroy(&priv->port);
- kfree(priv);
- return ret;
-}
-
-static void kgdb_nmi_tty_cleanup(struct tty_struct *tty)
-{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
-
- tty->driver_data = NULL;
- tty_port_destroy(&priv->port);
- kfree(priv);
-}
-
-static int kgdb_nmi_tty_open(struct tty_struct *tty, struct file *file)
-{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
- unsigned int mode = file->f_flags & O_ACCMODE;
- int ret;
-
- ret = tty_port_open(&priv->port, tty, file);
- if (!ret && (mode == O_RDONLY || mode == O_RDWR))
- atomic_inc(&kgdb_nmi_num_readers);
-
- return ret;
-}
-
-static void kgdb_nmi_tty_close(struct tty_struct *tty, struct file *file)
-{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
- unsigned int mode = file->f_flags & O_ACCMODE;
-
- if (mode == O_RDONLY || mode == O_RDWR)
- atomic_dec(&kgdb_nmi_num_readers);
-
- tty_port_close(&priv->port, tty, file);
-}
-
-static void kgdb_nmi_tty_hangup(struct tty_struct *tty)
-{
- struct kgdb_nmi_tty_priv *priv = tty->driver_data;
-
- tty_port_hangup(&priv->port);
-}
-
-static unsigned int kgdb_nmi_tty_write_room(struct tty_struct *tty)
-{
- /* Actually, we can handle any amount as we use polled writes. */
- return 2048;
-}
-
-static ssize_t kgdb_nmi_tty_write(struct tty_struct *tty, const u8 *buf,
- size_t c)
-{
- int i;
-
- for (i = 0; i < c; i++)
- dbg_io_ops->write_char(buf[i]);
- return c;
-}
-
-static const struct tty_operations kgdb_nmi_tty_ops = {
- .open = kgdb_nmi_tty_open,
- .close = kgdb_nmi_tty_close,
- .install = kgdb_nmi_tty_install,
- .cleanup = kgdb_nmi_tty_cleanup,
- .hangup = kgdb_nmi_tty_hangup,
- .write_room = kgdb_nmi_tty_write_room,
- .write = kgdb_nmi_tty_write,
-};
-
-int kgdb_register_nmi_console(void)
-{
- int ret;
-
- if (!arch_kgdb_ops.enable_nmi)
- return 0;
-
- kgdb_nmi_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW);
- if (IS_ERR(kgdb_nmi_tty_driver)) {
- pr_err("%s: cannot allocate tty\n", __func__);
- return PTR_ERR(kgdb_nmi_tty_driver);
- }
- kgdb_nmi_tty_driver->driver_name = "ttyNMI";
- kgdb_nmi_tty_driver->name = "ttyNMI";
- kgdb_nmi_tty_driver->num = 1;
- kgdb_nmi_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
- kgdb_nmi_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- kgdb_nmi_tty_driver->init_termios = tty_std_termios;
- tty_termios_encode_baud_rate(&kgdb_nmi_tty_driver->init_termios,
- KGDB_NMI_BAUD, KGDB_NMI_BAUD);
- tty_set_operations(kgdb_nmi_tty_driver, &kgdb_nmi_tty_ops);
-
- ret = tty_register_driver(kgdb_nmi_tty_driver);
- if (ret) {
- pr_err("%s: can't register tty driver: %d\n", __func__, ret);
- goto err_drv_reg;
- }
-
- register_console(&kgdb_nmi_console);
-
- return 0;
-err_drv_reg:
- tty_driver_kref_put(kgdb_nmi_tty_driver);
- return ret;
-}
-EXPORT_SYMBOL_GPL(kgdb_register_nmi_console);
-
-int kgdb_unregister_nmi_console(void)
-{
- int ret;
-
- if (!arch_kgdb_ops.enable_nmi)
- return 0;
- arch_kgdb_ops.enable_nmi(0);
-
- ret = unregister_console(&kgdb_nmi_console);
- if (ret)
- return ret;
-
- tty_unregister_driver(kgdb_nmi_tty_driver);
- tty_driver_kref_put(kgdb_nmi_tty_driver);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(kgdb_unregister_nmi_console);
diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c
index 7ce7bb164005..85f6c5a76e0f 100644
--- a/drivers/tty/serial/kgdboc.c
+++ b/drivers/tty/serial/kgdboc.c
@@ -19,6 +19,7 @@
#include <linux/console.h>
#include <linux/vt_kern.h>
#include <linux/input.h>
+#include <linux/irq_work.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
@@ -48,6 +49,25 @@ static struct kgdb_io kgdboc_earlycon_io_ops;
static int (*earlycon_orig_exit)(struct console *con);
#endif /* IS_BUILTIN(CONFIG_KGDB_SERIAL_CONSOLE) */
+/*
+ * When we leave the debug trap handler we need to reset the keyboard status
+ * (since the original keyboard state gets partially clobbered by kdb use of
+ * the keyboard).
+ *
+ * The path to deliver the reset is somewhat circuitous.
+ *
+ * To deliver the reset we register an input handler, reset the keyboard and
+ * then deregister the input handler. However, to get this done right, we do
+ * have to carefully manage the calling context because we can only register
+ * input handlers from task context.
+ *
+ * In particular we need to trigger the action from the debug trap handler with
+ * all its NMI and/or NMI-like oddities. To solve this the kgdboc trap exit code
+ * (the "post_exception" callback) uses irq_work_queue(), which is NMI-safe, to
+ * schedule a callback from a hardirq context. From there we have to defer the
+ * work again, this time using schedule_work(), to get a callback using the
+ * system workqueue, which runs in task context.
+ */
#ifdef CONFIG_KDB_KEYBOARD
static int kgdboc_reset_connect(struct input_handler *handler,
struct input_dev *dev,
@@ -99,10 +119,17 @@ static void kgdboc_restore_input_helper(struct work_struct *dummy)
static DECLARE_WORK(kgdboc_restore_input_work, kgdboc_restore_input_helper);
+static void kgdboc_queue_restore_input_helper(struct irq_work *unused)
+{
+ schedule_work(&kgdboc_restore_input_work);
+}
+
+static DEFINE_IRQ_WORK(kgdboc_restore_input_irq_work, kgdboc_queue_restore_input_helper);
+
static void kgdboc_restore_input(void)
{
if (likely(system_state == SYSTEM_RUNNING))
- schedule_work(&kgdboc_restore_input_work);
+ irq_work_queue(&kgdboc_restore_input_irq_work);
}
static int kgdboc_register_kbd(char **cptr)
@@ -133,6 +160,7 @@ static void kgdboc_unregister_kbd(void)
i--;
}
}
+ irq_work_sync(&kgdboc_restore_input_irq_work);
flush_work(&kgdboc_restore_input_work);
}
#else /* ! CONFIG_KDB_KEYBOARD */
@@ -158,8 +186,6 @@ static void cleanup_kgdboc(void)
if (configured != 1)
return;
- if (kgdb_unregister_nmi_console())
- return;
kgdboc_unregister_kbd();
kgdb_unregister_io_module(&kgdboc_io_ops);
}
@@ -222,16 +248,10 @@ do_register:
if (err)
goto noconfig;
- err = kgdb_register_nmi_console();
- if (err)
- goto nmi_con_failed;
-
configured = 1;
return 0;
-nmi_con_failed:
- kgdb_unregister_io_module(&kgdboc_io_ops);
noconfig:
kgdboc_unregister_kbd();
configured = 0;
diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c
index a0731773ce75..58a3ab030d67 100644
--- a/drivers/tty/serial/lantiq.c
+++ b/drivers/tty/serial/lantiq.c
@@ -915,7 +915,7 @@ MODULE_DEVICE_TABLE(of, ltq_asc_match);
static struct platform_driver lqasc_driver = {
.probe = lqasc_probe,
- .remove_new = lqasc_remove,
+ .remove = lqasc_remove,
.driver = {
.name = DRVNAME,
.of_match_table = ltq_asc_match,
diff --git a/drivers/tty/serial/liteuart.c b/drivers/tty/serial/liteuart.c
index 3ce369f76349..3a0960c97c77 100644
--- a/drivers/tty/serial/liteuart.c
+++ b/drivers/tty/serial/liteuart.c
@@ -96,7 +96,7 @@ static void liteuart_stop_rx(struct uart_port *port)
struct liteuart_port *uart = to_liteuart_port(port);
/* just delete timer */
- del_timer(&uart->timer);
+ timer_delete(&uart->timer);
}
static void liteuart_rx_chars(struct uart_port *port)
@@ -220,7 +220,7 @@ static void liteuart_shutdown(struct uart_port *port)
if (port->irq)
free_irq(port->irq, port);
else
- del_timer_sync(&uart->timer);
+ timer_delete_sync(&uart->timer);
}
static void liteuart_set_termios(struct uart_port *port, struct ktermios *new,
@@ -353,7 +353,7 @@ MODULE_DEVICE_TABLE(of, liteuart_of_match);
static struct platform_driver liteuart_platform_driver = {
.probe = liteuart_probe,
- .remove_new = liteuart_remove,
+ .remove = liteuart_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = liteuart_of_match,
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
index 3e4ac46de1bc..42c5f9bc18b7 100644
--- a/drivers/tty/serial/lpc32xx_hs.c
+++ b/drivers/tty/serial/lpc32xx_hs.c
@@ -695,7 +695,7 @@ MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids);
static struct platform_driver serial_hs_lpc32xx_driver = {
.probe = serial_hs_lpc32xx_probe,
- .remove_new = serial_hs_lpc32xx_remove,
+ .remove = serial_hs_lpc32xx_remove,
.suspend = serial_hs_lpc32xx_suspend,
.resume = serial_hs_lpc32xx_resume,
.driver = {
diff --git a/drivers/tty/serial/ma35d1_serial.c b/drivers/tty/serial/ma35d1_serial.c
index 19f0a305cc43..285b0fe41a86 100644
--- a/drivers/tty/serial/ma35d1_serial.c
+++ b/drivers/tty/serial/ma35d1_serial.c
@@ -688,12 +688,13 @@ static int ma35d1serial_probe(struct platform_device *pdev)
struct uart_ma35d1_port *up;
int ret = 0;
- if (pdev->dev.of_node) {
- ret = of_alias_get_id(pdev->dev.of_node, "serial");
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d\n", ret);
- return ret;
- }
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ ret = of_alias_get_id(pdev->dev.of_node, "serial");
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to get alias/pdev id, errno %d\n", ret);
+ return ret;
}
up = &ma35d1serial_ports[ret];
up->port.line = ret;
@@ -793,12 +794,12 @@ static int ma35d1serial_resume(struct platform_device *dev)
static struct platform_driver ma35d1serial_driver = {
.probe = ma35d1serial_probe,
- .remove_new = ma35d1serial_remove,
+ .remove = ma35d1serial_remove,
.suspend = ma35d1serial_suspend,
.resume = ma35d1serial_resume,
.driver = {
.name = "ma35d1-uart",
- .of_match_table = of_match_ptr(ma35d1_serial_of_match),
+ .of_match_table = ma35d1_serial_of_match,
},
};
diff --git a/drivers/tty/serial/max3100.c b/drivers/tty/serial/max3100.c
index 5efb2b593be3..f2dd83692b2c 100644
--- a/drivers/tty/serial/max3100.c
+++ b/drivers/tty/serial/max3100.c
@@ -1,6 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- *
* Copyright (C) 2008 Christian Pellegrin <chripell@evolware.org>
*
* Notes: the MAX3100 doesn't provide an interrupt on CTS so we have
@@ -8,24 +7,6 @@
* writing conf clears FIFO buffer and we cannot have this interrupt
* always asking us for attention.
*
- * Example platform data:
-
- static struct plat_max3100 max3100_plat_data = {
- .loopback = 0,
- .crystal = 0,
- .poll_time = 100,
- };
-
- static struct spi_board_info spi_board_info[] = {
- {
- .modalias = "max3100",
- .platform_data = &max3100_plat_data,
- .irq = IRQ_EINT12,
- .max_speed_hz = 5*1000*1000,
- .chip_select = 0,
- },
- };
-
* The initial minor number is 209 in the low-density serial port:
* mknod /dev/ttyMAX0 c 204 209
*/
@@ -35,18 +16,23 @@
/* 4 MAX3100s should be enough for everyone */
#define MAX_MAX3100 4
+#include <linux/container_of.h>
#include <linux/delay.h>
-#include <linux/slab.h>
#include <linux/device.h>
+#include <linux/freezer.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/property.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
+#include <linux/slab.h>
#include <linux/spi/spi.h>
-#include <linux/freezer.h>
-#include <linux/tty.h>
#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/types.h>
-#include <linux/serial_max3100.h>
+#include <linux/unaligned.h>
#define MAX3100_C (1<<14)
#define MAX3100_D (0<<14)
@@ -110,10 +96,8 @@ struct max3100_port {
#define MAX3100_7BIT 4
int rx_enabled; /* if we should rx chars */
- int irq; /* irq assigned to the max3100 */
-
int minor; /* minor number */
- int crystal; /* 1 if 3.6864Mhz crystal 0 for 1.8432 */
+ int loopback_commit; /* need to change loopback */
int loopback; /* 1 if we are in loopback mode */
/* for handling irqs: need workqueue since we do spi_sync */
@@ -124,15 +108,14 @@ struct max3100_port {
/* need to know we are suspending to avoid deadlock on workqueue */
int suspending;
- /* hook for suspending MAX3100 via dedicated pin */
- void (*max3100_hw_suspend) (int suspend);
-
- /* poll time (in ms) for ctrl lines */
- int poll_time;
- /* and its timer */
struct timer_list timer;
};
+static inline struct max3100_port *to_max3100_port(struct uart_port *port)
+{
+ return container_of(port, struct max3100_port, port);
+}
+
static struct max3100_port *max3100s[MAX_MAX3100]; /* the chips */
static DEFINE_MUTEX(max3100s_lock); /* race on probe */
@@ -170,28 +153,10 @@ static void max3100_calc_parity(struct max3100_port *s, u16 *c)
*c |= max3100_do_parity(s, *c) << 8;
}
-static void max3100_work(struct work_struct *w);
-
-static void max3100_dowork(struct max3100_port *s)
-{
- if (!s->force_end_work && !freezing(current) && !s->suspending)
- queue_work(s->workqueue, &s->work);
-}
-
-static void max3100_timeout(struct timer_list *t)
-{
- struct max3100_port *s = from_timer(s, t, timer);
-
- if (s->port.state) {
- max3100_dowork(s);
- mod_timer(&s->timer, jiffies + s->poll_time);
- }
-}
-
static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx)
{
struct spi_message message;
- u16 etx, erx;
+ __be16 etx, erx;
int status;
struct spi_transfer tran = {
.tx_buf = &etx,
@@ -213,7 +178,7 @@ static int max3100_sr(struct max3100_port *s, u16 tx, u16 *rx)
return 0;
}
-static int max3100_handlerx(struct max3100_port *s, u16 rx)
+static int max3100_handlerx_unlocked(struct max3100_port *s, u16 rx)
{
unsigned int status = 0;
int ret = 0, cts;
@@ -254,13 +219,25 @@ static int max3100_handlerx(struct max3100_port *s, u16 rx)
return ret;
}
+static int max3100_handlerx(struct max3100_port *s, u16 rx)
+{
+ unsigned long flags;
+ int ret;
+
+ uart_port_lock_irqsave(&s->port, &flags);
+ ret = max3100_handlerx_unlocked(s, rx);
+ uart_port_unlock_irqrestore(&s->port, flags);
+ return ret;
+}
+
static void max3100_work(struct work_struct *w)
{
struct max3100_port *s = container_of(w, struct max3100_port, work);
+ struct tty_port *tport = &s->port.state->port;
+ unsigned char ch;
+ int conf, cconf, cloopback, crts;
int rxchars;
u16 tx, rx;
- int conf, cconf, crts;
- struct circ_buf *xmit = &s->port.state->xmit;
dev_dbg(&s->spi->dev, "%s\n", __func__);
@@ -270,11 +247,15 @@ static void max3100_work(struct work_struct *w)
conf = s->conf;
cconf = s->conf_commit;
s->conf_commit = 0;
+ cloopback = s->loopback_commit;
+ s->loopback_commit = 0;
crts = s->rts_commit;
s->rts_commit = 0;
spin_unlock(&s->conf_lock);
if (cconf)
max3100_sr(s, MAX3100_WC | conf, &rx);
+ if (cloopback)
+ max3100_sr(s, 0x4001, &rx);
if (crts) {
max3100_sr(s, MAX3100_WD | MAX3100_TE |
(s->rts ? MAX3100_RTS : 0), &rx);
@@ -290,10 +271,9 @@ static void max3100_work(struct work_struct *w)
tx = s->port.x_char;
s->port.icount.tx++;
s->port.x_char = 0;
- } else if (!uart_circ_empty(xmit) &&
- !uart_tx_stopped(&s->port)) {
- tx = xmit->buf[xmit->tail];
- uart_xmit_advance(&s->port, 1);
+ } else if (!uart_tx_stopped(&s->port) &&
+ uart_fifo_get(&s->port, &ch)) {
+ tx = ch;
}
if (tx != 0xffff) {
max3100_calc_parity(s, &tx);
@@ -307,19 +287,33 @@ static void max3100_work(struct work_struct *w)
tty_flip_buffer_push(&s->port.state->port);
rxchars = 0;
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&s->port);
} while (!s->force_end_work &&
!freezing(current) &&
((rx & MAX3100_R) ||
- (!uart_circ_empty(xmit) &&
+ (!kfifo_is_empty(&tport->xmit_fifo) &&
!uart_tx_stopped(&s->port))));
if (rxchars > 0)
tty_flip_buffer_push(&s->port.state->port);
}
+static void max3100_dowork(struct max3100_port *s)
+{
+ if (!s->force_end_work && !freezing(current) && !s->suspending)
+ queue_work(s->workqueue, &s->work);
+}
+
+static void max3100_timeout(struct timer_list *t)
+{
+ struct max3100_port *s = from_timer(s, t, timer);
+
+ max3100_dowork(s);
+ mod_timer(&s->timer, jiffies + uart_poll_timeout(&s->port));
+}
+
static irqreturn_t max3100_irq(int irqno, void *dev_id)
{
struct max3100_port *s = dev_id;
@@ -332,20 +326,15 @@ static irqreturn_t max3100_irq(int irqno, void *dev_id)
static void max3100_enable_ms(struct uart_port *port)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
- if (s->poll_time > 0)
- mod_timer(&s->timer, jiffies);
+ mod_timer(&s->timer, jiffies);
dev_dbg(&s->spi->dev, "%s\n", __func__);
}
static void max3100_start_tx(struct uart_port *port)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
dev_dbg(&s->spi->dev, "%s\n", __func__);
@@ -354,9 +343,7 @@ static void max3100_start_tx(struct uart_port *port)
static void max3100_stop_rx(struct uart_port *port)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
dev_dbg(&s->spi->dev, "%s\n", __func__);
@@ -370,9 +357,7 @@ static void max3100_stop_rx(struct uart_port *port)
static unsigned int max3100_tx_empty(struct uart_port *port)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
dev_dbg(&s->spi->dev, "%s\n", __func__);
@@ -383,9 +368,7 @@ static unsigned int max3100_tx_empty(struct uart_port *port)
static unsigned int max3100_get_mctrl(struct uart_port *port)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
dev_dbg(&s->spi->dev, "%s\n", __func__);
@@ -397,21 +380,25 @@ static unsigned int max3100_get_mctrl(struct uart_port *port)
static void max3100_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
- int rts;
+ struct max3100_port *s = to_max3100_port(port);
+ int loopback, rts;
dev_dbg(&s->spi->dev, "%s\n", __func__);
+ loopback = (mctrl & TIOCM_LOOP) > 0;
rts = (mctrl & TIOCM_RTS) > 0;
spin_lock(&s->conf_lock);
+ if (s->loopback != loopback) {
+ s->loopback = loopback;
+ s->loopback_commit = 1;
+ }
if (s->rts != rts) {
s->rts = rts;
s->rts_commit = 1;
- max3100_dowork(s);
}
+ if (s->loopback_commit || s->rts_commit)
+ max3100_dowork(s);
spin_unlock(&s->conf_lock);
}
@@ -419,10 +406,9 @@ static void
max3100_set_termios(struct uart_port *port, struct ktermios *termios,
const struct ktermios *old)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
- int baud = 0;
+ struct max3100_port *s = to_max3100_port(port);
+ unsigned int baud = port->uartclk / 16;
+ unsigned int baud230400 = (baud == 230400) ? 1 : 0;
unsigned cflag;
u32 param_new, param_mask, parity = 0;
@@ -435,40 +421,40 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios,
param_new = s->conf & MAX3100_BAUD;
switch (baud) {
case 300:
- if (s->crystal)
+ if (baud230400)
baud = s->baud;
else
param_new = 15;
break;
case 600:
- param_new = 14 + s->crystal;
+ param_new = 14 + baud230400;
break;
case 1200:
- param_new = 13 + s->crystal;
+ param_new = 13 + baud230400;
break;
case 2400:
- param_new = 12 + s->crystal;
+ param_new = 12 + baud230400;
break;
case 4800:
- param_new = 11 + s->crystal;
+ param_new = 11 + baud230400;
break;
case 9600:
- param_new = 10 + s->crystal;
+ param_new = 10 + baud230400;
break;
case 19200:
- param_new = 9 + s->crystal;
+ param_new = 9 + baud230400;
break;
case 38400:
- param_new = 8 + s->crystal;
+ param_new = 8 + baud230400;
break;
case 57600:
- param_new = 1 + s->crystal;
+ param_new = 1 + baud230400;
break;
case 115200:
- param_new = 0 + s->crystal;
+ param_new = 0 + baud230400;
break;
case 230400:
- if (s->crystal)
+ if (baud230400)
param_new = 0;
else
baud = s->baud;
@@ -520,9 +506,7 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios,
MAX3100_STATUS_PE | MAX3100_STATUS_FE |
MAX3100_STATUS_OE;
- if (s->poll_time > 0)
- del_timer_sync(&s->timer);
-
+ timer_delete_sync(&s->timer);
uart_update_timeout(port, termios->c_cflag, baud);
spin_lock(&s->conf_lock);
@@ -538,9 +522,8 @@ max3100_set_termios(struct uart_port *port, struct ktermios *termios,
static void max3100_shutdown(struct uart_port *port)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
+ u16 rx;
dev_dbg(&s->spi->dev, "%s\n", __func__);
@@ -549,38 +532,29 @@ static void max3100_shutdown(struct uart_port *port)
s->force_end_work = 1;
- if (s->poll_time > 0)
- del_timer_sync(&s->timer);
+ timer_delete_sync(&s->timer);
if (s->workqueue) {
destroy_workqueue(s->workqueue);
s->workqueue = NULL;
}
- if (s->irq)
- free_irq(s->irq, s);
+ if (port->irq)
+ free_irq(port->irq, s);
/* set shutdown mode to save power */
- if (s->max3100_hw_suspend)
- s->max3100_hw_suspend(1);
- else {
- u16 tx, rx;
-
- tx = MAX3100_WC | MAX3100_SHDN;
- max3100_sr(s, tx, &rx);
- }
+ max3100_sr(s, MAX3100_WC | MAX3100_SHDN, &rx);
}
static int max3100_startup(struct uart_port *port)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
char b[12];
+ int ret;
dev_dbg(&s->spi->dev, "%s\n", __func__);
s->conf = MAX3100_RM;
- s->baud = s->crystal ? 230400 : 115200;
+ s->baud = port->uartclk / 16;
s->rx_enabled = 1;
if (s->suspending)
@@ -598,23 +572,15 @@ static int max3100_startup(struct uart_port *port)
}
INIT_WORK(&s->work, max3100_work);
- if (request_irq(s->irq, max3100_irq,
- IRQF_TRIGGER_FALLING, "max3100", s) < 0) {
- dev_warn(&s->spi->dev, "cannot allocate irq %d\n", s->irq);
- s->irq = 0;
+ ret = request_irq(port->irq, max3100_irq, IRQF_TRIGGER_FALLING, "max3100", s);
+ if (ret < 0) {
+ dev_warn(&s->spi->dev, "cannot allocate irq %d\n", port->irq);
+ port->irq = 0;
destroy_workqueue(s->workqueue);
s->workqueue = NULL;
return -EBUSY;
}
- if (s->loopback) {
- u16 tx, rx;
- tx = 0x4001;
- max3100_sr(s, tx, &rx);
- }
-
- if (s->max3100_hw_suspend)
- s->max3100_hw_suspend(0);
s->conf_commit = 1;
max3100_dowork(s);
/* wait for clock to settle */
@@ -627,9 +593,7 @@ static int max3100_startup(struct uart_port *port)
static const char *max3100_type(struct uart_port *port)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
dev_dbg(&s->spi->dev, "%s\n", __func__);
@@ -638,18 +602,14 @@ static const char *max3100_type(struct uart_port *port)
static void max3100_release_port(struct uart_port *port)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
dev_dbg(&s->spi->dev, "%s\n", __func__);
}
static void max3100_config_port(struct uart_port *port, int flags)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
dev_dbg(&s->spi->dev, "%s\n", __func__);
@@ -660,9 +620,7 @@ static void max3100_config_port(struct uart_port *port, int flags)
static int max3100_verify_port(struct uart_port *port,
struct serial_struct *ser)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
int ret = -EINVAL;
dev_dbg(&s->spi->dev, "%s\n", __func__);
@@ -674,18 +632,14 @@ static int max3100_verify_port(struct uart_port *port,
static void max3100_stop_tx(struct uart_port *port)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
dev_dbg(&s->spi->dev, "%s\n", __func__);
}
static int max3100_request_port(struct uart_port *port)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
dev_dbg(&s->spi->dev, "%s\n", __func__);
return 0;
@@ -693,9 +647,7 @@ static int max3100_request_port(struct uart_port *port)
static void max3100_break_ctl(struct uart_port *port, int break_state)
{
- struct max3100_port *s = container_of(port,
- struct max3100_port,
- port);
+ struct max3100_port *s = to_max3100_port(port);
dev_dbg(&s->spi->dev, "%s\n", __func__);
}
@@ -731,74 +683,59 @@ static int uart_driver_registered;
static int max3100_probe(struct spi_device *spi)
{
+ struct device *dev = &spi->dev;
int i, retval;
- struct plat_max3100 *pdata;
- u16 tx, rx;
+ u16 rx;
mutex_lock(&max3100s_lock);
if (!uart_driver_registered) {
- uart_driver_registered = 1;
retval = uart_register_driver(&max3100_uart_driver);
if (retval) {
- printk(KERN_ERR "Couldn't register max3100 uart driver\n");
mutex_unlock(&max3100s_lock);
- return retval;
+ return dev_err_probe(dev, retval, "Couldn't register max3100 uart driver\n");
}
+
+ uart_driver_registered = 1;
}
for (i = 0; i < MAX_MAX3100; i++)
if (!max3100s[i])
break;
if (i == MAX_MAX3100) {
- dev_warn(&spi->dev, "too many MAX3100 chips\n");
mutex_unlock(&max3100s_lock);
- return -ENOMEM;
+ return dev_err_probe(dev, -ENOMEM, "too many MAX3100 chips\n");
}
max3100s[i] = kzalloc(sizeof(struct max3100_port), GFP_KERNEL);
if (!max3100s[i]) {
- dev_warn(&spi->dev,
- "kmalloc for max3100 structure %d failed!\n", i);
mutex_unlock(&max3100s_lock);
return -ENOMEM;
}
max3100s[i]->spi = spi;
- max3100s[i]->irq = spi->irq;
spin_lock_init(&max3100s[i]->conf_lock);
spi_set_drvdata(spi, max3100s[i]);
- pdata = dev_get_platdata(&spi->dev);
- max3100s[i]->crystal = pdata->crystal;
- max3100s[i]->loopback = pdata->loopback;
- max3100s[i]->poll_time = msecs_to_jiffies(pdata->poll_time);
- if (pdata->poll_time > 0 && max3100s[i]->poll_time == 0)
- max3100s[i]->poll_time = 1;
- max3100s[i]->max3100_hw_suspend = pdata->max3100_hw_suspend;
max3100s[i]->minor = i;
timer_setup(&max3100s[i]->timer, max3100_timeout, 0);
dev_dbg(&spi->dev, "%s: adding port %d\n", __func__, i);
- max3100s[i]->port.irq = max3100s[i]->irq;
- max3100s[i]->port.uartclk = max3100s[i]->crystal ? 3686400 : 1843200;
+ max3100s[i]->port.irq = spi->irq;
max3100s[i]->port.fifosize = 16;
max3100s[i]->port.ops = &max3100_ops;
max3100s[i]->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
max3100s[i]->port.line = i;
max3100s[i]->port.type = PORT_MAX3100;
max3100s[i]->port.dev = &spi->dev;
+
+ /* Read clock frequency from a property, uart_add_one_port() will fail if it's not set */
+ device_property_read_u32(dev, "clock-frequency", &max3100s[i]->port.uartclk);
+
retval = uart_add_one_port(&max3100_uart_driver, &max3100s[i]->port);
if (retval < 0)
- dev_warn(&spi->dev,
- "uart_add_one_port failed for line %d with error %d\n",
- i, retval);
+ dev_err_probe(dev, retval, "uart_add_one_port failed for line %d\n", i);
/* set shutdown mode to save power. Will be woken-up on open */
- if (max3100s[i]->max3100_hw_suspend)
- max3100s[i]->max3100_hw_suspend(1);
- else {
- tx = MAX3100_WC | MAX3100_SHDN;
- max3100_sr(max3100s[i], tx, &rx);
- }
+ max3100_sr(max3100s[i], MAX3100_WC | MAX3100_SHDN, &rx);
mutex_unlock(&max3100s_lock);
return 0;
}
@@ -830,32 +767,25 @@ static void max3100_remove(struct spi_device *spi)
}
pr_debug("removing max3100 driver\n");
uart_unregister_driver(&max3100_uart_driver);
+ uart_driver_registered = 0;
mutex_unlock(&max3100s_lock);
}
-#ifdef CONFIG_PM_SLEEP
-
static int max3100_suspend(struct device *dev)
{
struct max3100_port *s = dev_get_drvdata(dev);
+ u16 rx;
dev_dbg(&s->spi->dev, "%s\n", __func__);
- disable_irq(s->irq);
+ disable_irq(s->port.irq);
s->suspending = 1;
uart_suspend_port(&max3100_uart_driver, &s->port);
- if (s->max3100_hw_suspend)
- s->max3100_hw_suspend(1);
- else {
- /* no HW suspend, so do SW one */
- u16 tx, rx;
-
- tx = MAX3100_WC | MAX3100_SHDN;
- max3100_sr(s, tx, &rx);
- }
+ /* no HW suspend, so do SW one */
+ max3100_sr(s, MAX3100_WC | MAX3100_SHDN, &rx);
return 0;
}
@@ -865,12 +795,10 @@ static int max3100_resume(struct device *dev)
dev_dbg(&s->spi->dev, "%s\n", __func__);
- if (s->max3100_hw_suspend)
- s->max3100_hw_suspend(0);
uart_resume_port(&max3100_uart_driver, &s->port);
s->suspending = 0;
- enable_irq(s->irq);
+ enable_irq(s->port.irq);
s->conf_commit = 1;
if (s->workqueue)
@@ -879,20 +807,29 @@ static int max3100_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume);
-#define MAX3100_PM_OPS (&max3100_pm_ops)
+static DEFINE_SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume);
+
+static const struct spi_device_id max3100_spi_id[] = {
+ { "max3100" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, max3100_spi_id);
-#else
-#define MAX3100_PM_OPS NULL
-#endif
+static const struct of_device_id max3100_of_match[] = {
+ { .compatible = "maxim,max3100" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max3100_of_match);
static struct spi_driver max3100_driver = {
.driver = {
.name = "max3100",
- .pm = MAX3100_PM_OPS,
+ .of_match_table = max3100_of_match,
+ .pm = pm_sleep_ptr(&max3100_pm_ops),
},
.probe = max3100_probe,
.remove = max3100_remove,
+ .id_table = max3100_spi_id,
};
module_spi_driver(max3100_driver);
@@ -900,4 +837,3 @@ module_spi_driver(max3100_driver);
MODULE_DESCRIPTION("MAX3100 driver");
MODULE_AUTHOR("Christian Pellegrin <chripell@evolware.org>");
MODULE_LICENSE("GPL");
-MODULE_ALIAS("spi:max3100");
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 14dd9cfaa9f7..35369a2f77b2 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -747,8 +747,9 @@ static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
static void max310x_handle_tx(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
- unsigned int txlen, to_send, until_end;
+ struct tty_port *tport = &port->state->port;
+ unsigned int txlen, to_send;
+ unsigned char *tail;
if (unlikely(port->x_char)) {
max310x_port_write(port, MAX310X_THR_REG, port->x_char);
@@ -757,32 +758,26 @@ static void max310x_handle_tx(struct uart_port *port)
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))
return;
- /* Get length of data pending in circular buffer */
- to_send = uart_circ_chars_pending(xmit);
- until_end = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
- if (likely(to_send)) {
+ /*
+ * It's a circ buffer -- wrap around.
+ * We could do that in one SPI transaction, but meh.
+ */
+ while (!kfifo_is_empty(&tport->xmit_fifo)) {
/* Limit to space available in TX FIFO */
txlen = max310x_port_read(port, MAX310X_TXFIFOLVL_REG);
txlen = port->fifosize - txlen;
- to_send = (to_send > txlen) ? txlen : to_send;
-
- if (until_end < to_send) {
- /*
- * It's a circ buffer -- wrap around.
- * We could do that in one SPI transaction, but meh.
- */
- max310x_batch_write(port, xmit->buf + xmit->tail, until_end);
- max310x_batch_write(port, xmit->buf, to_send - until_end);
- } else {
- max310x_batch_write(port, xmit->buf + xmit->tail, to_send);
- }
+ if (!txlen)
+ break;
+
+ to_send = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, txlen);
+ max310x_batch_write(port, tail, to_send);
uart_xmit_advance(port, to_send);
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
@@ -1478,7 +1473,7 @@ static struct regmap_config regcfg = {
.reg_bits = 8,
.val_bits = 8,
.write_flag_mask = MAX310X_WRITE_BIT,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.max_register = MAX310X_REG_1F,
.writeable_reg = max310x_reg_writeable,
.volatile_reg = max310x_reg_volatile,
@@ -1582,7 +1577,7 @@ static int max310x_i2c_extended_reg_enable(struct device *dev, bool enable)
static struct regmap_config regcfg_i2c = {
.reg_bits = 8,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.writeable_reg = max310x_reg_writeable,
.volatile_reg = max310x_reg_volatile,
.precious_reg = max310x_reg_precious,
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index b0604d6da025..93e7dda4d39a 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -462,7 +462,7 @@ static const struct uart_ops mcf_uart_ops = {
.verify_port = mcf_verify_port,
};
-static struct mcf_uart mcf_ports[4];
+static struct mcf_uart mcf_ports[10];
#define MCF_MAXPORTS ARRAY_SIZE(mcf_ports)
@@ -616,7 +616,7 @@ static void mcf_remove(struct platform_device *pdev)
static struct platform_driver mcf_platform_driver = {
.probe = mcf_probe,
- .remove_new = mcf_remove,
+ .remove = mcf_remove,
.driver = {
.name = "mcfuart",
},
diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c
index 8048fa542fc4..9cc15449b673 100644
--- a/drivers/tty/serial/men_z135_uart.c
+++ b/drivers/tty/serial/men_z135_uart.c
@@ -293,17 +293,14 @@ static void men_z135_handle_rx(struct men_z135_port *uart)
static void men_z135_handle_tx(struct men_z135_port *uart)
{
struct uart_port *port = &uart->port;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
+ unsigned char *tail;
+ unsigned int n, txfree;
u32 txc;
u32 wptr;
int qlen;
- int n;
- int txfree;
- int head;
- int tail;
- int s;
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
goto out;
if (uart_tx_stopped(port))
@@ -313,7 +310,7 @@ static void men_z135_handle_tx(struct men_z135_port *uart)
goto out;
/* calculate bytes to copy */
- qlen = uart_circ_chars_pending(xmit);
+ qlen = kfifo_len(&tport->xmit_fifo);
if (qlen <= 0)
goto out;
@@ -345,21 +342,18 @@ static void men_z135_handle_tx(struct men_z135_port *uart)
if (n <= 0)
goto irq_en;
- head = xmit->head & (UART_XMIT_SIZE - 1);
- tail = xmit->tail & (UART_XMIT_SIZE - 1);
-
- s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail;
- n = min(n, s);
+ n = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
+ min_t(unsigned int, UART_XMIT_SIZE, n));
+ memcpy_toio(port->membase + MEN_Z135_TX_RAM, tail, n);
- memcpy_toio(port->membase + MEN_Z135_TX_RAM, &xmit->buf[xmit->tail], n);
iowrite32(n & 0x3ff, port->membase + MEN_Z135_TX_CTRL);
uart_xmit_advance(port, n);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
irq_en:
- if (!uart_circ_empty(xmit))
+ if (!kfifo_is_empty(&tport->xmit_fifo))
men_z135_reg_set(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
else
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
@@ -926,4 +920,4 @@ MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MEN 16z135 High Speed UART");
MODULE_ALIAS("mcb:16z135");
-MODULE_IMPORT_NS(MCB);
+MODULE_IMPORT_NS("MCB");
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c
index 6feac459c0cf..a6cb2a535f9d 100644
--- a/drivers/tty/serial/meson_uart.c
+++ b/drivers/tty/serial/meson_uart.c
@@ -141,8 +141,8 @@ static void meson_uart_shutdown(struct uart_port *port)
static void meson_uart_start_tx(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
- unsigned int ch;
+ struct tty_port *tport = &port->state->port;
+ unsigned char ch;
u32 val;
if (uart_tx_stopped(port)) {
@@ -158,21 +158,19 @@ static void meson_uart_start_tx(struct uart_port *port)
continue;
}
- if (uart_circ_empty(xmit))
+ if (!uart_fifo_get(port, &ch))
break;
- ch = xmit->buf[xmit->tail];
writel(ch, port->membase + AML_UART_WFIFO);
- uart_xmit_advance(port, 1);
}
- if (!uart_circ_empty(xmit)) {
+ if (!kfifo_is_empty(&tport->xmit_fifo)) {
val = readl(port->membase + AML_UART_CONTROL);
val |= AML_UART_TX_INT_EN;
writel(val, port->membase + AML_UART_CONTROL);
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
@@ -844,7 +842,7 @@ MODULE_DEVICE_TABLE(of, meson_uart_dt_match);
static struct platform_driver meson_uart_platform_driver = {
.probe = meson_uart_probe,
- .remove_new = meson_uart_remove,
+ .remove = meson_uart_remove,
.driver = {
.name = "meson_uart",
.of_match_table = meson_uart_dt_match,
diff --git a/drivers/tty/serial/milbeaut_usio.c b/drivers/tty/serial/milbeaut_usio.c
index da4c6f7e2a30..059bea18dbab 100644
--- a/drivers/tty/serial/milbeaut_usio.c
+++ b/drivers/tty/serial/milbeaut_usio.c
@@ -72,7 +72,7 @@ static void mlb_usio_stop_tx(struct uart_port *port)
static void mlb_usio_tx_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
int count;
writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FTIE,
@@ -87,7 +87,7 @@ static void mlb_usio_tx_chars(struct uart_port *port)
port->x_char = 0;
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
mlb_usio_stop_tx(port);
return;
}
@@ -96,12 +96,13 @@ static void mlb_usio_tx_chars(struct uart_port *port)
(readw(port->membase + MLB_USIO_REG_FBYTE) & 0xff);
do {
- writew(xmit->buf[xmit->tail], port->membase + MLB_USIO_REG_DR);
+ unsigned char ch;
- uart_xmit_advance(port, 1);
- if (uart_circ_empty(xmit))
+ if (!uart_fifo_get(port, &ch))
break;
+ writew(ch, port->membase + MLB_USIO_REG_DR);
+ port->icount.tx++;
} while (--count > 0);
writew(readw(port->membase + MLB_USIO_REG_FCR) & ~MLB_USIO_FCR_FDRQ,
@@ -110,10 +111,10 @@ static void mlb_usio_tx_chars(struct uart_port *port)
writeb(readb(port->membase + MLB_USIO_REG_SCR) | MLB_USIO_SCR_TBIE,
port->membase + MLB_USIO_REG_SCR);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
mlb_usio_stop_tx(port);
}
@@ -569,7 +570,7 @@ MODULE_DEVICE_TABLE(of, mlb_usio_dt_ids);
static struct platform_driver mlb_usio_driver = {
.probe = mlb_usio_probe,
- .remove_new = mlb_usio_remove,
+ .remove = mlb_usio_remove,
.driver = {
.name = USIO_NAME,
.of_match_table = mlb_usio_dt_ids,
diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c
index 95dae5e27b28..37eb701b0b46 100644
--- a/drivers/tty/serial/mpc52xx_uart.c
+++ b/drivers/tty/serial/mpc52xx_uart.c
@@ -1351,7 +1351,6 @@ static const struct uart_ops mpc52xx_uart_ops = {
.startup = mpc52xx_uart_startup,
.shutdown = mpc52xx_uart_shutdown,
.set_termios = mpc52xx_uart_set_termios,
-/* .pm = mpc52xx_uart_pm, Not supported yet */
.type = mpc52xx_uart_type,
.release_port = mpc52xx_uart_release_port,
.request_port = mpc52xx_uart_request_port,
@@ -1621,7 +1620,7 @@ mpc52xx_console_setup(struct console *co, char *options)
(void *)port->mapbase, port->membase,
port->irq, port->uartclk);
- /* Setup the port parameters accoding to options */
+ /* Setup the port parameters according to options */
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
@@ -1843,7 +1842,7 @@ MODULE_DEVICE_TABLE(of, mpc52xx_uart_of_match);
static struct platform_driver mpc52xx_uart_of_driver = {
.probe = mpc52xx_uart_of_probe,
- .remove_new = mpc52xx_uart_of_remove,
+ .remove = mpc52xx_uart_of_remove,
#ifdef CONFIG_PM
.suspend = mpc52xx_uart_of_suspend,
.resume = mpc52xx_uart_of_resume,
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index d27c4c8c84e1..3449945493ce 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -161,11 +161,16 @@ enum {
struct msm_dma {
struct dma_chan *chan;
enum dma_data_direction dir;
- dma_addr_t phys;
- unsigned char *virt;
+ union {
+ struct {
+ dma_addr_t phys;
+ unsigned char *virt;
+ unsigned int count;
+ } rx;
+ struct scatterlist tx_sg;
+ };
dma_cookie_t cookie;
u32 enable_bit;
- unsigned int count;
struct dma_async_tx_descriptor *desc;
};
@@ -249,8 +254,12 @@ static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
unsigned int mapped;
u32 val;
- mapped = dma->count;
- dma->count = 0;
+ if (dma->dir == DMA_TO_DEVICE) {
+ mapped = sg_dma_len(&dma->tx_sg);
+ } else {
+ mapped = dma->rx.count;
+ dma->rx.count = 0;
+ }
dmaengine_terminate_all(dma->chan);
@@ -265,8 +274,13 @@ static void msm_stop_dma(struct uart_port *port, struct msm_dma *dma)
val &= ~dma->enable_bit;
msm_write(port, val, UARTDM_DMEN);
- if (mapped)
- dma_unmap_single(dev, dma->phys, mapped, dma->dir);
+ if (mapped) {
+ if (dma->dir == DMA_TO_DEVICE) {
+ dma_unmap_sg(dev, &dma->tx_sg, 1, dma->dir);
+ sg_init_table(&dma->tx_sg, 1);
+ } else
+ dma_unmap_single(dev, dma->rx.phys, mapped, dma->dir);
+ }
}
static void msm_release_dma(struct msm_port *msm_port)
@@ -285,7 +299,7 @@ static void msm_release_dma(struct msm_port *msm_port)
if (dma->chan) {
msm_stop_dma(&msm_port->uart, dma);
dma_release_channel(dma->chan);
- kfree(dma->virt);
+ kfree(dma->rx.virt);
}
memset(dma, 0, sizeof(*dma));
@@ -357,8 +371,8 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base)
of_property_read_u32(dev->of_node, "qcom,rx-crci", &crci);
- dma->virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL);
- if (!dma->virt)
+ dma->rx.virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL);
+ if (!dma->rx.virt)
goto rel_rx;
memset(&conf, 0, sizeof(conf));
@@ -385,7 +399,7 @@ static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base)
return;
err:
- kfree(dma->virt);
+ kfree(dma->rx.virt);
rel_rx:
dma_release_channel(dma->chan);
no_rx:
@@ -420,7 +434,7 @@ static void msm_start_tx(struct uart_port *port)
struct msm_dma *dma = &msm_port->tx_dma;
/* Already started in DMA mode */
- if (dma->count)
+ if (sg_dma_len(&dma->tx_sg))
return;
msm_port->imr |= MSM_UART_IMR_TXLEV;
@@ -438,7 +452,7 @@ static void msm_complete_tx_dma(void *args)
{
struct msm_port *msm_port = args;
struct uart_port *port = &msm_port->uart;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
struct msm_dma *dma = &msm_port->tx_dma;
struct dma_tx_state state;
unsigned long flags;
@@ -448,12 +462,12 @@ static void msm_complete_tx_dma(void *args)
uart_port_lock_irqsave(port, &flags);
/* Already stopped */
- if (!dma->count)
+ if (!sg_dma_len(&dma->tx_sg))
goto done;
dmaengine_tx_status(dma->chan, dma->cookie, &state);
- dma_unmap_single(port->dev, dma->phys, dma->count, dma->dir);
+ dma_unmap_sg(port->dev, &dma->tx_sg, 1, dma->dir);
val = msm_read(port, UARTDM_DMEN);
val &= ~dma->enable_bit;
@@ -464,15 +478,15 @@ static void msm_complete_tx_dma(void *args)
msm_write(port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR);
}
- count = dma->count - state.residue;
+ count = sg_dma_len(&dma->tx_sg) - state.residue;
uart_xmit_advance(port, count);
- dma->count = 0;
+ sg_init_table(&dma->tx_sg, 1);
/* Restore "Tx FIFO below watermark" interrupt */
msm_port->imr |= MSM_UART_IMR_TXLEV;
msm_write(port, msm_port->imr, MSM_UART_IMR);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
msm_handle_tx(port);
@@ -482,22 +496,24 @@ done:
static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
{
- struct circ_buf *xmit = &msm_port->uart.state->xmit;
struct uart_port *port = &msm_port->uart;
+ struct tty_port *tport = &port->state->port;
struct msm_dma *dma = &msm_port->tx_dma;
- void *cpu_addr;
+ unsigned int mapped;
int ret;
u32 val;
- cpu_addr = &xmit->buf[xmit->tail];
+ sg_init_table(&dma->tx_sg, 1);
+ kfifo_dma_out_prepare(&tport->xmit_fifo, &dma->tx_sg, 1, count);
- dma->phys = dma_map_single(port->dev, cpu_addr, count, dma->dir);
- ret = dma_mapping_error(port->dev, dma->phys);
- if (ret)
- return ret;
+ mapped = dma_map_sg(port->dev, &dma->tx_sg, 1, dma->dir);
+ if (!mapped) {
+ ret = -EIO;
+ goto zero_sg;
+ }
- dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys,
- count, DMA_MEM_TO_DEV,
+ dma->desc = dmaengine_prep_slave_sg(dma->chan, &dma->tx_sg, 1,
+ DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT |
DMA_PREP_FENCE);
if (!dma->desc) {
@@ -520,8 +536,6 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
msm_port->imr &= ~MSM_UART_IMR_TXLEV;
msm_write(port, msm_port->imr, MSM_UART_IMR);
- dma->count = count;
-
val = msm_read(port, UARTDM_DMEN);
val |= dma->enable_bit;
@@ -536,7 +550,9 @@ static int msm_handle_tx_dma(struct msm_port *msm_port, unsigned int count)
dma_async_issue_pending(dma->chan);
return 0;
unmap:
- dma_unmap_single(port->dev, dma->phys, count, dma->dir);
+ dma_unmap_sg(port->dev, &dma->tx_sg, 1, dma->dir);
+zero_sg:
+ sg_init_table(&dma->tx_sg, 1);
return ret;
}
@@ -553,7 +569,7 @@ static void msm_complete_rx_dma(void *args)
uart_port_lock_irqsave(port, &flags);
/* Already stopped */
- if (!dma->count)
+ if (!dma->rx.count)
goto done;
val = msm_read(port, UARTDM_DMEN);
@@ -570,14 +586,14 @@ static void msm_complete_rx_dma(void *args)
port->icount.rx += count;
- dma->count = 0;
+ dma->rx.count = 0;
- dma_unmap_single(port->dev, dma->phys, UARTDM_RX_SIZE, dma->dir);
+ dma_unmap_single(port->dev, dma->rx.phys, UARTDM_RX_SIZE, dma->dir);
for (i = 0; i < count; i++) {
char flag = TTY_NORMAL;
- if (msm_port->break_detected && dma->virt[i] == 0) {
+ if (msm_port->break_detected && dma->rx.virt[i] == 0) {
port->icount.brk++;
flag = TTY_BREAK;
msm_port->break_detected = false;
@@ -588,9 +604,9 @@ static void msm_complete_rx_dma(void *args)
if (!(port->read_status_mask & MSM_UART_SR_RX_BREAK))
flag = TTY_NORMAL;
- sysrq = uart_prepare_sysrq_char(port, dma->virt[i]);
+ sysrq = uart_prepare_sysrq_char(port, dma->rx.virt[i]);
if (!sysrq)
- tty_insert_flip_char(tport, dma->virt[i], flag);
+ tty_insert_flip_char(tport, dma->rx.virt[i], flag);
}
msm_start_rx_dma(msm_port);
@@ -614,13 +630,13 @@ static void msm_start_rx_dma(struct msm_port *msm_port)
if (!dma->chan)
return;
- dma->phys = dma_map_single(uart->dev, dma->virt,
+ dma->rx.phys = dma_map_single(uart->dev, dma->rx.virt,
UARTDM_RX_SIZE, dma->dir);
- ret = dma_mapping_error(uart->dev, dma->phys);
+ ret = dma_mapping_error(uart->dev, dma->rx.phys);
if (ret)
goto sw_mode;
- dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys,
+ dma->desc = dmaengine_prep_slave_single(dma->chan, dma->rx.phys,
UARTDM_RX_SIZE, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (!dma->desc)
@@ -648,7 +664,7 @@ static void msm_start_rx_dma(struct msm_port *msm_port)
msm_write(uart, msm_port->imr, MSM_UART_IMR);
- dma->count = UARTDM_RX_SIZE;
+ dma->rx.count = UARTDM_RX_SIZE;
dma_async_issue_pending(dma->chan);
@@ -668,7 +684,7 @@ static void msm_start_rx_dma(struct msm_port *msm_port)
return;
unmap:
- dma_unmap_single(uart->dev, dma->phys, UARTDM_RX_SIZE, dma->dir);
+ dma_unmap_single(uart->dev, dma->rx.phys, UARTDM_RX_SIZE, dma->dir);
sw_mode:
/*
@@ -831,8 +847,8 @@ static void msm_handle_rx(struct uart_port *port)
static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count)
{
- struct circ_buf *xmit = &port->state->xmit;
struct msm_port *msm_port = to_msm_port(port);
+ struct tty_port *tport = &port->state->port;
unsigned int num_chars;
unsigned int tf_pointer = 0;
void __iomem *tf;
@@ -846,8 +862,7 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count)
msm_reset_dm_count(port, tx_count);
while (tf_pointer < tx_count) {
- int i;
- char buf[4] = { 0 };
+ unsigned char buf[4] = { 0 };
if (!(msm_read(port, MSM_UART_SR) & MSM_UART_SR_TX_READY))
break;
@@ -858,26 +873,23 @@ static void msm_handle_tx_pio(struct uart_port *port, unsigned int tx_count)
else
num_chars = 1;
- for (i = 0; i < num_chars; i++)
- buf[i] = xmit->buf[xmit->tail + i];
-
+ num_chars = uart_fifo_out(port, buf, num_chars);
iowrite32_rep(tf, buf, 1);
- uart_xmit_advance(port, num_chars);
tf_pointer += num_chars;
}
/* disable tx interrupts if nothing more to send */
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
msm_stop_tx(port);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
static void msm_handle_tx(struct uart_port *port)
{
struct msm_port *msm_port = to_msm_port(port);
- struct circ_buf *xmit = &msm_port->uart.state->xmit;
+ struct tty_port *tport = &port->state->port;
struct msm_dma *dma = &msm_port->tx_dma;
unsigned int pio_count, dma_count, dma_min;
char buf[4] = { 0 };
@@ -901,13 +913,13 @@ static void msm_handle_tx(struct uart_port *port)
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
msm_stop_tx(port);
return;
}
- pio_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
- dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ dma_count = pio_count = kfifo_out_linear(&tport->xmit_fifo, NULL,
+ UART_XMIT_SIZE);
dma_min = 1; /* Always DMA */
if (msm_port->is_uartdm > UARTDM_1P3) {
@@ -955,7 +967,7 @@ static irqreturn_t msm_uart_irq(int irq, void *dev_id)
}
if (misr & (MSM_UART_IMR_RXLEV | MSM_UART_IMR_RXSTALE)) {
- if (dma->count) {
+ if (dma->rx.count) {
val = MSM_UART_CR_CMD_STALE_EVENT_DISABLE;
msm_write(port, val, MSM_UART_CR);
val = MSM_UART_CR_CMD_RESET_STALE_INT;
@@ -1734,6 +1746,12 @@ msm_serial_early_console_setup_dm(struct earlycon_device *device,
if (!device->port.membase)
return -ENODEV;
+ /* Disable DM / single-character modes */
+ msm_write(&device->port, 0, UARTDM_DMEN);
+ msm_write(&device->port, MSM_UART_CR_CMD_RESET_RX, MSM_UART_CR);
+ msm_write(&device->port, MSM_UART_CR_CMD_RESET_TX, MSM_UART_CR);
+ msm_write(&device->port, MSM_UART_CR_TX_ENABLE, MSM_UART_CR);
+
device->con->write = msm_serial_early_write_dm;
return 0;
}
@@ -1882,7 +1900,7 @@ static const struct dev_pm_ops msm_serial_dev_pm_ops = {
};
static struct platform_driver msm_platform_driver = {
- .remove_new = msm_serial_remove,
+ .remove = msm_serial_remove,
.probe = msm_serial_probe,
.driver = {
.name = "msm_serial",
diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c
index 85ce1e9af44a..b417faead20f 100644
--- a/drivers/tty/serial/mux.c
+++ b/drivers/tty/serial/mux.c
@@ -563,7 +563,7 @@ static void __exit mux_exit(void)
{
/* Delete the Mux timer. */
if(port_cnt > 0) {
- del_timer_sync(&mux_timer);
+ timer_delete_sync(&mux_timer);
#ifdef CONFIG_SERIAL_MUX_CONSOLE
unregister_console(&mux_console);
#endif
diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c
index 0255646bc175..5de57b77abdb 100644
--- a/drivers/tty/serial/mvebu-uart.c
+++ b/drivers/tty/serial/mvebu-uart.c
@@ -219,12 +219,10 @@ static void mvebu_uart_stop_tx(struct uart_port *port)
static void mvebu_uart_start_tx(struct uart_port *port)
{
unsigned int ctl;
- struct circ_buf *xmit = &port->state->xmit;
+ unsigned char c;
- if (IS_EXTENDED(port) && !uart_circ_empty(xmit)) {
- writel(xmit->buf[xmit->tail], port->membase + UART_TSH(port));
- uart_xmit_advance(port, 1);
- }
+ if (IS_EXTENDED(port) && uart_fifo_get(port, &c))
+ writel(c, port->membase + UART_TSH(port));
ctl = readl(port->membase + UART_INTR(port));
ctl |= CTRL_TX_RDY_INT(port);
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index 1e8853eae504..cc65c9fb6446 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -517,7 +517,7 @@ static void mxs_auart_tx_chars(struct mxs_auart_port *s);
static void dma_tx_callback(void *param)
{
struct mxs_auart_port *s = param;
- struct circ_buf *xmit = &s->port.state->xmit;
+ struct tty_port *tport = &s->port.state->port;
dma_unmap_sg(s->dev, &s->tx_sgl, 1, DMA_TO_DEVICE);
@@ -526,7 +526,7 @@ static void dma_tx_callback(void *param)
smp_mb__after_atomic();
/* wake up the possible processes. */
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&s->port);
mxs_auart_tx_chars(s);
@@ -568,33 +568,22 @@ static int mxs_auart_dma_tx(struct mxs_auart_port *s, int size)
static void mxs_auart_tx_chars(struct mxs_auart_port *s)
{
- struct circ_buf *xmit = &s->port.state->xmit;
+ struct tty_port *tport = &s->port.state->port;
bool pending;
u8 ch;
if (auart_dma_enabled(s)) {
u32 i = 0;
- int size;
void *buffer = s->tx_dma_buf;
if (test_and_set_bit(MXS_AUART_DMA_TX_SYNC, &s->flags))
return;
- while (!uart_circ_empty(xmit) && !uart_tx_stopped(&s->port)) {
- size = min_t(u32, UART_XMIT_SIZE - i,
- CIRC_CNT_TO_END(xmit->head,
- xmit->tail,
- UART_XMIT_SIZE));
- memcpy(buffer + i, xmit->buf + xmit->tail, size);
- xmit->tail = (xmit->tail + size) & (UART_XMIT_SIZE - 1);
-
- i += size;
- if (i >= UART_XMIT_SIZE)
- break;
- }
-
if (uart_tx_stopped(&s->port))
mxs_auart_stop_tx(&s->port);
+ else
+ i = kfifo_out(&tport->xmit_fifo, buffer,
+ UART_XMIT_SIZE);
if (i) {
mxs_auart_dma_tx(s, i);
@@ -1715,7 +1704,7 @@ static void mxs_auart_remove(struct platform_device *pdev)
static struct platform_driver mxs_auart_driver = {
.probe = mxs_auart_probe,
- .remove_new = mxs_auart_remove,
+ .remove = mxs_auart_remove,
.driver = {
.name = "mxs-auart",
.of_match_table = mxs_auart_dt_ids,
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 9be1c871cf11..0b85f47ff19e 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1093,7 +1093,6 @@ static void __maybe_unused wait_for_xmitr(struct uart_omap_port *up)
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
- tmout = 1000000;
for (tmout = 1000000; tmout; tmout--) {
unsigned int msr = serial_in(up, UART_MSR);
@@ -1803,7 +1802,7 @@ MODULE_DEVICE_TABLE(of, omap_serial_of_match);
static struct platform_driver serial_omap_driver = {
.probe = serial_omap_probe,
- .remove_new = serial_omap_remove,
+ .remove = serial_omap_remove,
.driver = {
.name = OMAP_SERIAL_DRIVER_NAME,
.pm = &serial_omap_dev_pm_ops,
diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c
index 8b60ac0ad7cd..0542882cfbbe 100644
--- a/drivers/tty/serial/owl-uart.c
+++ b/drivers/tty/serial/owl-uart.c
@@ -730,7 +730,7 @@ static void owl_uart_remove(struct platform_device *pdev)
static struct platform_driver owl_uart_platform_driver = {
.probe = owl_uart_probe,
- .remove_new = owl_uart_remove,
+ .remove = owl_uart_remove,
.driver = {
.name = "owl-uart",
.of_match_table = owl_uart_dt_matches,
@@ -761,4 +761,5 @@ static void __exit owl_uart_exit(void)
module_init(owl_uart_init);
module_exit(owl_uart_exit);
+MODULE_DESCRIPTION("Actions Semi Owl family serial console");
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 89257cddf540..508e8c6f01d4 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -808,7 +808,7 @@ static int dma_handle_rx(struct eg20t_port *priv)
static unsigned int handle_tx(struct eg20t_port *priv)
{
struct uart_port *port = &priv->port;
- struct circ_buf *xmit = &port->state->xmit;
+ unsigned char ch;
int fifo_size;
int tx_empty;
@@ -830,9 +830,9 @@ static unsigned int handle_tx(struct eg20t_port *priv)
fifo_size--;
}
- while (!uart_tx_stopped(port) && !uart_circ_empty(xmit) && fifo_size) {
- iowrite8(xmit->buf[xmit->tail], priv->membase + PCH_UART_THR);
- uart_xmit_advance(port, 1);
+ while (!uart_tx_stopped(port) && fifo_size &&
+ uart_fifo_get(port, &ch)) {
+ iowrite8(ch, priv->membase + PCH_UART_THR);
fifo_size--;
tx_empty = 0;
}
@@ -850,14 +850,14 @@ static unsigned int handle_tx(struct eg20t_port *priv)
static unsigned int dma_handle_tx(struct eg20t_port *priv)
{
struct uart_port *port = &priv->port;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
struct scatterlist *sg;
int nent;
int fifo_size;
struct dma_async_tx_descriptor *desc;
+ unsigned int bytes, tail;
int num;
int i;
- int bytes;
int size;
int rem;
@@ -886,7 +886,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
fifo_size--;
}
- bytes = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ bytes = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE);
if (!bytes) {
dev_dbg(priv->port.dev, "%s 0 bytes return\n", __func__);
pch_uart_hal_disable_interrupt(priv, PCH_UART_HAL_TX_INT);
@@ -920,10 +920,10 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
for (i = 0; i < num; i++, sg++) {
if (i == (num - 1))
- sg_set_page(sg, virt_to_page(xmit->buf),
+ sg_set_page(sg, virt_to_page(tport->xmit_buf),
rem, fifo_size * i);
else
- sg_set_page(sg, virt_to_page(xmit->buf),
+ sg_set_page(sg, virt_to_page(tport->xmit_buf),
size, fifo_size * i);
}
@@ -937,8 +937,7 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
priv->nent = nent;
for (i = 0; i < nent; i++, sg++) {
- sg->offset = (xmit->tail & (UART_XMIT_SIZE - 1)) +
- fifo_size * i;
+ sg->offset = tail + fifo_size * i;
sg_dma_address(sg) = (sg_dma_address(sg) &
~(UART_XMIT_SIZE - 1)) + sg->offset;
if (i == (nent - 1))
@@ -1516,7 +1515,6 @@ static const struct uart_ops pch_uart_ops = {
.startup = pch_uart_startup,
.shutdown = pch_uart_shutdown,
.set_termios = pch_uart_set_termios,
-/* .pm = pch_uart_pm, Not supported yet */
.type = pch_uart_type,
.release_port = pch_uart_release_port,
.request_port = pch_uart_request_port,
diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c
index bbb46e6e98a2..14d50bd7f1bd 100644
--- a/drivers/tty/serial/pic32_uart.c
+++ b/drivers/tty/serial/pic32_uart.c
@@ -8,11 +8,11 @@
* Sorin-Andrei Pistirica <andrei.pistirica@microchip.com>
*/
+#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
-#include <linux/of_gpio.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -342,7 +342,7 @@ static void pic32_uart_do_rx(struct uart_port *port)
static void pic32_uart_do_tx(struct uart_port *port)
{
struct pic32_sport *sport = to_pic32_sport(port);
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
unsigned int max_count = PIC32_UART_TX_FIFO_DEPTH;
if (port->x_char) {
@@ -357,7 +357,7 @@ static void pic32_uart_do_tx(struct uart_port *port)
return;
}
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
goto txq_empty;
/* keep stuffing chars into uart tx buffer
@@ -371,21 +371,20 @@ static void pic32_uart_do_tx(struct uart_port *port)
*/
while (!(PIC32_UART_STA_UTXBF &
pic32_uart_readl(sport, PIC32_UART_STA))) {
- unsigned int c = xmit->buf[xmit->tail];
+ unsigned char c;
+ if (!uart_fifo_get(port, &c))
+ break;
pic32_uart_writel(sport, PIC32_UART_TX, c);
- uart_xmit_advance(port, 1);
- if (uart_circ_empty(xmit))
- break;
if (--max_count == 0)
break;
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
goto txq_empty;
return;
@@ -957,7 +956,7 @@ MODULE_DEVICE_TABLE(of, pic32_serial_dt_ids);
static struct platform_driver pic32_uart_platform_driver = {
.probe = pic32_uart_probe,
- .remove_new = pic32_uart_remove,
+ .remove = pic32_uart_remove,
.driver = {
.name = PIC32_DEV_NAME,
.of_match_table = of_match_ptr(pic32_serial_dt_ids),
diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c
index 92195f984de1..e3a919328695 100644
--- a/drivers/tty/serial/pmac_zilog.c
+++ b/drivers/tty/serial/pmac_zilog.c
@@ -333,7 +333,8 @@ static void pmz_status_handle(struct uart_pmac_port *uap)
static void pmz_transmit_chars(struct uart_pmac_port *uap)
{
- struct circ_buf *xmit;
+ struct tty_port *tport;
+ unsigned char ch;
if (ZS_IS_CONS(uap)) {
unsigned char status = read_zsreg(uap, R0);
@@ -384,8 +385,8 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap)
if (uap->port.state == NULL)
goto ack_tx_int;
- xmit = &uap->port.state->xmit;
- if (uart_circ_empty(xmit)) {
+ tport = &uap->port.state->port;
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
uart_write_wakeup(&uap->port);
goto ack_tx_int;
}
@@ -393,12 +394,11 @@ static void pmz_transmit_chars(struct uart_pmac_port *uap)
goto ack_tx_int;
uap->flags |= PMACZILOG_FLAG_TX_ACTIVE;
- write_zsdata(uap, xmit->buf[xmit->tail]);
+ WARN_ON(!uart_fifo_get(&uap->port, &ch));
+ write_zsdata(uap, ch);
zssync(uap);
- uart_xmit_advance(&uap->port, 1);
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
return;
@@ -606,15 +606,15 @@ static void pmz_start_tx(struct uart_port *port)
port->icount.tx++;
port->x_char = 0;
} else {
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
+ unsigned char ch;
- if (uart_circ_empty(xmit))
+ if (!uart_fifo_get(&uap->port, &ch))
return;
- write_zsdata(uap, xmit->buf[xmit->tail]);
+ write_zsdata(uap, ch);
zssync(uap);
- uart_xmit_advance(port, 1);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&uap->port);
}
}
@@ -1681,7 +1681,7 @@ static void pmz_dispose_port(struct uart_pmac_port *uap)
memset(uap, 0, sizeof(struct uart_pmac_port));
}
-static int __init pmz_attach(struct platform_device *pdev)
+static int pmz_attach(struct platform_device *pdev)
{
struct uart_pmac_port *uap;
int i;
@@ -1700,7 +1700,7 @@ static int __init pmz_attach(struct platform_device *pdev)
return uart_add_one_port(&pmz_uart_reg, &uap->port);
}
-static void __exit pmz_detach(struct platform_device *pdev)
+static void pmz_detach(struct platform_device *pdev)
{
struct uart_pmac_port *uap = platform_get_drvdata(pdev);
@@ -1775,7 +1775,8 @@ static struct macio_driver pmz_driver = {
#else
static struct platform_driver pmz_driver = {
- .remove_new = __exit_p(pmz_detach),
+ .probe = pmz_attach,
+ .remove = pmz_detach,
.driver = {
.name = "scc",
},
@@ -1823,7 +1824,7 @@ static int __init init_pmz(void)
#ifdef CONFIG_PPC_PMAC
return macio_register_driver(&pmz_driver);
#else
- return platform_driver_probe(&pmz_driver, pmz_attach);
+ return platform_driver_register(&pmz_driver);
#endif
}
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
index f9f7ac1a10df..a80ce7aaf309 100644
--- a/drivers/tty/serial/qcom_geni_serial.c
+++ b/drivers/tty/serial/qcom_geni_serial.c
@@ -124,13 +124,14 @@ struct qcom_geni_serial_port {
dma_addr_t tx_dma_addr;
dma_addr_t rx_dma_addr;
bool setup;
- unsigned int baud;
+ unsigned long poll_timeout_us;
unsigned long clk_rate;
void *rx_buf;
u32 loopback;
bool brk;
unsigned int tx_remaining;
+ unsigned int tx_queued;
int wakeup_irq;
bool rx_tx_swap;
bool cts_rts_swap;
@@ -144,6 +145,10 @@ static const struct uart_ops qcom_geni_uart_pops;
static struct uart_driver qcom_geni_console_driver;
static struct uart_driver qcom_geni_uart_driver;
+static void __qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport);
+static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport);
+static int qcom_geni_serial_port_setup(struct uart_port *uport);
+
static inline struct qcom_geni_serial_port *to_dev_port(struct uart_port *uport)
{
return container_of(uport, struct qcom_geni_serial_port, uport);
@@ -265,27 +270,18 @@ static bool qcom_geni_serial_secondary_active(struct uart_port *uport)
return readl(uport->membase + SE_GENI_STATUS) & S_GENI_CMD_ACTIVE;
}
-static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
- int offset, int field, bool set)
+static bool qcom_geni_serial_poll_bitfield(struct uart_port *uport,
+ unsigned int offset, u32 field, u32 val)
{
u32 reg;
struct qcom_geni_serial_port *port;
- unsigned int baud;
- unsigned int fifo_bits;
unsigned long timeout_us = 20000;
struct qcom_geni_private_data *private_data = uport->private_data;
if (private_data->drv) {
port = to_dev_port(uport);
- baud = port->baud;
- if (!baud)
- baud = 115200;
- fifo_bits = port->tx_fifo_depth * port->tx_fifo_width;
- /*
- * Total polling iterations based on FIFO worth of bytes to be
- * sent at current baud. Add a little fluff to the wait.
- */
- timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500;
+ if (port->poll_timeout_us)
+ timeout_us = port->poll_timeout_us;
}
/*
@@ -295,7 +291,7 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
timeout_us = DIV_ROUND_UP(timeout_us, 10) * 10;
while (timeout_us) {
reg = readl(uport->membase + offset);
- if ((bool)(reg & field) == set)
+ if ((reg & field) == val)
return true;
udelay(10);
timeout_us -= 10;
@@ -303,6 +299,12 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
return false;
}
+static bool qcom_geni_serial_poll_bit(struct uart_port *uport,
+ unsigned int offset, u32 field, bool set)
+{
+ return qcom_geni_serial_poll_bitfield(uport, offset, field, set ? field : 0);
+}
+
static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size)
{
u32 m_cmd;
@@ -315,18 +317,16 @@ static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size)
static void qcom_geni_serial_poll_tx_done(struct uart_port *uport)
{
int done;
- u32 irq_clear = M_CMD_DONE_EN;
done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
M_CMD_DONE_EN, true);
if (!done) {
writel(M_GENI_CMD_ABORT, uport->membase +
SE_GENI_M_CMD_CTRL_REG);
- irq_clear |= M_CMD_ABORT_EN;
qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
M_CMD_ABORT_EN, true);
+ writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
}
- writel(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR);
}
static void qcom_geni_serial_abort_rx(struct uart_port *uport)
@@ -386,17 +386,44 @@ static int qcom_geni_serial_get_char(struct uart_port *uport)
static void qcom_geni_serial_poll_put_char(struct uart_port *uport,
unsigned char c)
{
- writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
+ if (qcom_geni_serial_main_active(uport)) {
+ qcom_geni_serial_poll_tx_done(uport);
+ __qcom_geni_serial_cancel_tx_cmd(uport);
+ }
+
+ writel(M_CMD_DONE_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
qcom_geni_serial_setup_tx(uport, 1);
- WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
- M_TX_FIFO_WATERMARK_EN, true));
writel(c, uport->membase + SE_GENI_TX_FIFOn);
- writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
qcom_geni_serial_poll_tx_done(uport);
}
+
+static int qcom_geni_serial_poll_init(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+ int ret;
+
+ if (!port->setup) {
+ ret = qcom_geni_serial_port_setup(uport);
+ if (ret)
+ return ret;
+ }
+
+ if (!qcom_geni_serial_secondary_active(uport))
+ geni_se_setup_s_cmd(&port->se, UART_START_READ, 0);
+
+ return 0;
+}
#endif
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
+static void qcom_geni_serial_drain_fifo(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+
+ qcom_geni_serial_poll_bitfield(uport, SE_GENI_M_GP_LENGTH, GP_LENGTH,
+ port->tx_queued);
+}
+
static void qcom_geni_serial_wr_char(struct uart_port *uport, unsigned char ch)
{
struct qcom_geni_private_data *private_data = uport->private_data;
@@ -431,6 +458,7 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s,
}
writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
+ writel(M_CMD_DONE_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
qcom_geni_serial_setup_tx(uport, bytes_to_send);
for (i = 0; i < count; ) {
size_t chars_to_write = 0;
@@ -469,10 +497,9 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
{
struct uart_port *uport;
struct qcom_geni_serial_port *port;
+ u32 m_irq_en, s_irq_en;
bool locked = true;
unsigned long flags;
- u32 geni_status;
- u32 irq_en;
WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS);
@@ -486,40 +513,28 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s,
else
uart_port_lock_irqsave(uport, &flags);
- geni_status = readl(uport->membase + SE_GENI_STATUS);
-
- if (!locked) {
- /*
- * We can only get here if an oops is in progress then we were
- * unable to get the lock. This means we can't safely access
- * our state variables like tx_remaining. About the best we
- * can do is wait for the FIFO to be empty before we start our
- * transfer, so we'll do that.
- */
- qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
- M_TX_FIFO_NOT_EMPTY_EN, false);
- } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) {
- /*
- * It seems we can't interrupt existing transfers if all data
- * has been sent, in which case we need to look for done first.
- */
- qcom_geni_serial_poll_tx_done(uport);
-
- if (!uart_circ_empty(&uport->state->xmit)) {
- irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
- writel(irq_en | M_TX_FIFO_WATERMARK_EN,
- uport->membase + SE_GENI_M_IRQ_EN);
- }
+ m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
+ s_irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN);
+ writel(0, uport->membase + SE_GENI_M_IRQ_EN);
+ writel(0, uport->membase + SE_GENI_S_IRQ_EN);
+
+ if (qcom_geni_serial_main_active(uport)) {
+ /* Wait for completion or drain FIFO */
+ if (!locked || port->tx_remaining == 0)
+ qcom_geni_serial_poll_tx_done(uport);
+ else
+ qcom_geni_serial_drain_fifo(uport);
+
+ qcom_geni_serial_cancel_tx_cmd(uport);
}
__qcom_geni_serial_console_write(uport, s, count);
+ writel(m_irq_en, uport->membase + SE_GENI_M_IRQ_EN);
+ writel(s_irq_en, uport->membase + SE_GENI_S_IRQ_EN);
- if (locked) {
- if (port->tx_remaining)
- qcom_geni_serial_setup_tx(uport, port->tx_remaining);
+ if (locked)
uart_port_unlock_irqrestore(uport, flags);
- }
}
static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
@@ -565,7 +580,7 @@ static void handle_rx_console(struct uart_port *uport, u32 bytes, bool drop)
}
#endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */
-static void handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop)
+static void handle_rx_uart(struct uart_port *uport, u32 bytes)
{
struct qcom_geni_serial_port *port = to_dev_port(uport);
struct tty_port *tport = &uport->state->port;
@@ -573,9 +588,8 @@ static void handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop)
ret = tty_insert_flip_string(tport, port->rx_buf, bytes);
if (ret != bytes) {
- dev_err(uport->dev, "%s:Unable to push data ret %d_bytes %d\n",
- __func__, ret, bytes);
- WARN_ON_ONCE(1);
+ dev_err_ratelimited(uport->dev, "failed to push data (%d < %u)\n",
+ ret, bytes);
}
uport->icount.rx += ret;
tty_flip_buffer_push(tport);
@@ -620,22 +634,24 @@ static void qcom_geni_serial_stop_tx_dma(struct uart_port *uport)
static void qcom_geni_serial_start_tx_dma(struct uart_port *uport)
{
struct qcom_geni_serial_port *port = to_dev_port(uport);
- struct circ_buf *xmit = &uport->state->xmit;
+ struct tty_port *tport = &uport->state->port;
unsigned int xmit_size;
+ u8 *tail;
int ret;
if (port->tx_dma_addr)
return;
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
return;
- xmit_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ xmit_size = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
+ UART_XMIT_SIZE);
qcom_geni_serial_setup_tx(uport, xmit_size);
- ret = geni_se_tx_dma_prep(&port->se, &xmit->buf[xmit->tail],
- xmit_size, &port->tx_dma_addr);
+ ret = geni_se_tx_dma_prep(&port->se, tail, xmit_size,
+ &port->tx_dma_addr);
if (ret) {
dev_err(uport->dev, "unable to start TX SE DMA: %d\n", ret);
qcom_geni_serial_stop_tx_dma(uport);
@@ -647,15 +663,25 @@ static void qcom_geni_serial_start_tx_dma(struct uart_port *uport)
static void qcom_geni_serial_start_tx_fifo(struct uart_port *uport)
{
+ unsigned char c;
u32 irq_en;
- if (qcom_geni_serial_main_active(uport) ||
- !qcom_geni_serial_tx_empty(uport))
- return;
+ /*
+ * Start a new transfer in case the previous command was cancelled and
+ * left data in the FIFO which may prevent the watermark interrupt
+ * from triggering. Note that the stale data is discarded.
+ */
+ if (!qcom_geni_serial_main_active(uport) &&
+ !qcom_geni_serial_tx_empty(uport)) {
+ if (uart_fifo_out(uport, &c, 1) == 1) {
+ writel(M_CMD_DONE_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
+ qcom_geni_serial_setup_tx(uport, 1);
+ writel(c, uport->membase + SE_GENI_TX_FIFOn);
+ }
+ }
irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN;
-
writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG);
writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
}
@@ -663,15 +689,16 @@ static void qcom_geni_serial_start_tx_fifo(struct uart_port *uport)
static void qcom_geni_serial_stop_tx_fifo(struct uart_port *uport)
{
u32 irq_en;
- struct qcom_geni_serial_port *port = to_dev_port(uport);
irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
irq_en &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN);
writel(0, uport->membase + SE_GENI_TX_WATERMARK_REG);
writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN);
- /* Possible stop tx is called multiple times. */
- if (!qcom_geni_serial_main_active(uport))
- return;
+}
+
+static void __qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
geni_se_cancel_m_cmd(&port->se);
if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS,
@@ -684,6 +711,19 @@ static void qcom_geni_serial_stop_tx_fifo(struct uart_port *uport)
writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR);
}
+static void qcom_geni_serial_cancel_tx_cmd(struct uart_port *uport)
+{
+ struct qcom_geni_serial_port *port = to_dev_port(uport);
+
+ if (!qcom_geni_serial_main_active(uport))
+ return;
+
+ __qcom_geni_serial_cancel_tx_cmd(uport);
+
+ port->tx_remaining = 0;
+ port->tx_queued = 0;
+}
+
static void qcom_geni_serial_handle_rx_fifo(struct uart_port *uport, bool drop)
{
u32 status;
@@ -764,17 +804,27 @@ static void qcom_geni_serial_start_rx_fifo(struct uart_port *uport)
static void qcom_geni_serial_stop_rx_dma(struct uart_port *uport)
{
struct qcom_geni_serial_port *port = to_dev_port(uport);
+ bool done;
if (!qcom_geni_serial_secondary_active(uport))
return;
geni_se_cancel_s_cmd(&port->se);
- qcom_geni_serial_poll_bit(uport, SE_GENI_S_IRQ_STATUS,
- S_CMD_CANCEL_EN, true);
-
- if (qcom_geni_serial_secondary_active(uport))
+ done = qcom_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT,
+ RX_EOT, true);
+ if (done) {
+ writel(RX_EOT | RX_DMA_DONE,
+ uport->membase + SE_DMA_RX_IRQ_CLR);
+ } else {
qcom_geni_serial_abort_rx(uport);
+ writel(1, uport->membase + SE_DMA_RX_FSM_RST);
+ qcom_geni_serial_poll_bit(uport, SE_DMA_RX_IRQ_STAT,
+ RX_RESET_DONE, true);
+ writel(RX_RESET_DONE | RX_DMA_DONE,
+ uport->membase + SE_DMA_RX_IRQ_CLR);
+ }
+
if (port->rx_dma_addr) {
geni_se_rx_dma_unprep(&port->se, port->rx_dma_addr,
DMA_RX_BUF_SIZE);
@@ -823,7 +873,7 @@ static void qcom_geni_serial_handle_rx_dma(struct uart_port *uport, bool drop)
}
if (!drop)
- handle_rx_uart(uport, rx_in, drop);
+ handle_rx_uart(uport, rx_in);
ret = geni_se_rx_dma_prep(&port->se, port->rx_buf,
DMA_RX_BUF_SIZE,
@@ -853,18 +903,14 @@ static void qcom_geni_serial_send_chunk_fifo(struct uart_port *uport,
unsigned int chunk)
{
struct qcom_geni_serial_port *port = to_dev_port(uport);
- struct circ_buf *xmit = &uport->state->xmit;
- unsigned int tx_bytes, c, remaining = chunk;
+ unsigned int tx_bytes, remaining = chunk;
u8 buf[BYTES_PER_FIFO_WORD];
while (remaining) {
memset(buf, 0, sizeof(buf));
tx_bytes = min(remaining, BYTES_PER_FIFO_WORD);
- for (c = 0; c < tx_bytes ; c++) {
- buf[c] = xmit->buf[xmit->tail];
- uart_xmit_advance(uport, 1);
- }
+ uart_fifo_out(uport, buf, tx_bytes);
iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1);
@@ -877,7 +923,7 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport,
bool done, bool active)
{
struct qcom_geni_serial_port *port = to_dev_port(uport);
- struct circ_buf *xmit = &uport->state->xmit;
+ struct tty_port *tport = &uport->state->port;
size_t avail;
size_t pending;
u32 status;
@@ -890,24 +936,29 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport,
if (active)
pending = port->tx_remaining;
else
- pending = uart_circ_chars_pending(xmit);
+ pending = kfifo_len(&tport->xmit_fifo);
- /* All data has been transmitted and acknowledged as received */
- if (!pending && !status && done) {
+ /* All data has been transmitted or command has been cancelled */
+ if (!pending && done) {
qcom_geni_serial_stop_tx_fifo(uport);
goto out_write_wakeup;
}
- avail = port->tx_fifo_depth - (status & TX_FIFO_WC);
+ if (active)
+ avail = port->tx_fifo_depth - (status & TX_FIFO_WC);
+ else
+ avail = port->tx_fifo_depth;
+
avail *= BYTES_PER_FIFO_WORD;
chunk = min(avail, pending);
if (!chunk)
goto out_write_wakeup;
- if (!port->tx_remaining) {
+ if (!active) {
qcom_geni_serial_setup_tx(uport, pending);
port->tx_remaining = pending;
+ port->tx_queued = 0;
irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN);
if (!(irq_en & M_TX_FIFO_WATERMARK_EN))
@@ -916,6 +967,7 @@ static void qcom_geni_serial_handle_tx_fifo(struct uart_port *uport,
}
qcom_geni_serial_send_chunk_fifo(uport, chunk);
+ port->tx_queued += chunk;
/*
* The tx fifo watermark is level triggered and latched. Though we had
@@ -933,24 +985,24 @@ out_write_wakeup:
uport->membase + SE_GENI_M_IRQ_EN);
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(uport);
}
static void qcom_geni_serial_handle_tx_dma(struct uart_port *uport)
{
struct qcom_geni_serial_port *port = to_dev_port(uport);
- struct circ_buf *xmit = &uport->state->xmit;
+ struct tty_port *tport = &uport->state->port;
uart_xmit_advance(uport, port->tx_remaining);
geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr, port->tx_remaining);
port->tx_dma_addr = 0;
port->tx_remaining = 0;
- if (!uart_circ_empty(xmit))
+ if (!kfifo_is_empty(&tport->xmit_fifo))
qcom_geni_serial_start_tx_dma(uport);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(uport);
}
@@ -1071,11 +1123,17 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport)
{
disable_irq(uport->irq);
- if (uart_console(uport))
- return;
-
+ uart_port_lock_irq(uport);
qcom_geni_serial_stop_tx(uport);
qcom_geni_serial_stop_rx(uport);
+
+ qcom_geni_serial_cancel_tx_cmd(uport);
+ uart_port_unlock_irq(uport);
+}
+
+static void qcom_geni_serial_flush_buffer(struct uart_port *uport)
+{
+ qcom_geni_serial_cancel_tx_cmd(uport);
}
static int qcom_geni_serial_port_setup(struct uart_port *uport)
@@ -1123,7 +1181,6 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport)
false, true, true);
geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2);
geni_se_select_mode(&port->se, port->dev_data->mode);
- qcom_geni_serial_start_rx(uport);
port->setup = true;
return 0;
@@ -1139,6 +1196,11 @@ static int qcom_geni_serial_startup(struct uart_port *uport)
if (ret)
return ret;
}
+
+ uart_port_lock_irq(uport);
+ qcom_geni_serial_start_rx(uport);
+ uart_port_unlock_irq(uport);
+
enable_irq(uport->irq);
return 0;
@@ -1222,11 +1284,10 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
unsigned long clk_rate;
u32 ver, sampling_rate;
unsigned int avg_bw_core;
+ unsigned long timeout;
- qcom_geni_serial_stop_rx(uport);
/* baud rate */
baud = uart_get_baud_rate(uport, termios, old, 300, 4000000);
- port->baud = baud;
sampling_rate = UART_OVERSAMPLING;
/* Sampling rate is halved for IP versions >= 2.5 */
@@ -1240,7 +1301,7 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
dev_err(port->se.dev,
"Couldn't find suitable clock rate for %u\n",
baud * sampling_rate);
- goto out_restart_rx;
+ return;
}
dev_dbg(port->se.dev, "desired_rate = %u, clk_rate = %lu, clk_div = %u\n",
@@ -1304,9 +1365,21 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
else
tx_trans_cfg |= UART_CTS_MASK;
- if (baud)
+ if (baud) {
uart_update_timeout(uport, termios->c_cflag, baud);
+ /*
+ * Make sure that qcom_geni_serial_poll_bitfield() waits for
+ * the FIFO, two-word intermediate transfer register and shift
+ * register to clear.
+ *
+ * Note that uart_fifo_timeout() also adds a 20 ms margin.
+ */
+ timeout = jiffies_to_usecs(uart_fifo_timeout(uport));
+ timeout += 3 * timeout / port->tx_fifo_depth;
+ WRITE_ONCE(port->poll_timeout_us, timeout);
+ }
+
if (!uart_console(uport))
writel(port->loopback,
uport->membase + SE_UART_LOOPBACK_CFG);
@@ -1319,8 +1392,6 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN);
writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG);
writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG);
-out_restart_rx:
- qcom_geni_serial_start_rx(uport);
}
#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE
@@ -1534,13 +1605,14 @@ static const struct uart_ops qcom_geni_console_pops = {
.request_port = qcom_geni_serial_request_port,
.config_port = qcom_geni_serial_config_port,
.shutdown = qcom_geni_serial_shutdown,
+ .flush_buffer = qcom_geni_serial_flush_buffer,
.type = qcom_geni_serial_get_type,
.set_mctrl = qcom_geni_serial_set_mctrl,
.get_mctrl = qcom_geni_serial_get_mctrl,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = qcom_geni_serial_get_char,
.poll_put_char = qcom_geni_serial_poll_put_char,
- .poll_init = qcom_geni_serial_port_setup,
+ .poll_init = qcom_geni_serial_poll_init,
#endif
.pm = qcom_geni_serial_pm,
};
@@ -1707,7 +1779,7 @@ static void qcom_geni_serial_remove(struct platform_device *pdev)
uart_remove_one_port(drv, &port->uport);
}
-static int qcom_geni_serial_sys_suspend(struct device *dev)
+static int qcom_geni_serial_suspend(struct device *dev)
{
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
struct uart_port *uport = &port->uport;
@@ -1724,7 +1796,7 @@ static int qcom_geni_serial_sys_suspend(struct device *dev)
return uart_suspend_port(private_data->drv, uport);
}
-static int qcom_geni_serial_sys_resume(struct device *dev)
+static int qcom_geni_serial_resume(struct device *dev)
{
int ret;
struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
@@ -1739,38 +1811,6 @@ static int qcom_geni_serial_sys_resume(struct device *dev)
return ret;
}
-static int qcom_geni_serial_sys_hib_resume(struct device *dev)
-{
- int ret = 0;
- struct uart_port *uport;
- struct qcom_geni_private_data *private_data;
- struct qcom_geni_serial_port *port = dev_get_drvdata(dev);
-
- uport = &port->uport;
- private_data = uport->private_data;
-
- if (uart_console(uport)) {
- geni_icc_set_tag(&port->se, QCOM_ICC_TAG_ALWAYS);
- geni_icc_set_bw(&port->se);
- ret = uart_resume_port(private_data->drv, uport);
- /*
- * For hibernation usecase clients for
- * console UART won't call port setup during restore,
- * hence call port setup for console uart.
- */
- qcom_geni_serial_port_setup(uport);
- } else {
- /*
- * Peripheral register settings are lost during hibernation.
- * Update setup flag such that port setup happens again
- * during next session. Clients of HS-UART will close and
- * open the port during hibernation.
- */
- port->setup = false;
- }
- return ret;
-}
-
static const struct qcom_geni_device_data qcom_geni_console_data = {
.console = true,
.mode = GENI_SE_FIFO,
@@ -1782,12 +1822,7 @@ static const struct qcom_geni_device_data qcom_geni_uart_data = {
};
static const struct dev_pm_ops qcom_geni_serial_pm_ops = {
- .suspend = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
- .resume = pm_sleep_ptr(qcom_geni_serial_sys_resume),
- .freeze = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
- .poweroff = pm_sleep_ptr(qcom_geni_serial_sys_suspend),
- .restore = pm_sleep_ptr(qcom_geni_serial_sys_hib_resume),
- .thaw = pm_sleep_ptr(qcom_geni_serial_sys_hib_resume),
+ SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_suspend, qcom_geni_serial_resume)
};
static const struct of_device_id qcom_geni_serial_match_table[] = {
@@ -1804,7 +1839,7 @@ static const struct of_device_id qcom_geni_serial_match_table[] = {
MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table);
static struct platform_driver qcom_geni_serial_platform_driver = {
- .remove_new = qcom_geni_serial_remove,
+ .remove = qcom_geni_serial_remove,
.probe = qcom_geni_serial_probe,
.driver = {
.name = "qcom_geni_serial",
diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c
index 82def9b8632a..87fa30d68687 100644
--- a/drivers/tty/serial/rda-uart.c
+++ b/drivers/tty/serial/rda-uart.c
@@ -330,8 +330,8 @@ static void rda_uart_set_termios(struct uart_port *port,
static void rda_uart_send_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
- unsigned int ch;
+ struct tty_port *tport = &port->state->port;
+ unsigned char ch;
u32 val;
if (uart_tx_stopped(port))
@@ -347,19 +347,14 @@ static void rda_uart_send_chars(struct uart_port *port)
port->x_char = 0;
}
- while (rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK) {
- if (uart_circ_empty(xmit))
- break;
-
- ch = xmit->buf[xmit->tail];
+ while ((rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK) &&
+ uart_fifo_get(port, &ch))
rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER);
- uart_xmit_advance(port, 1);
- }
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (!uart_circ_empty(xmit)) {
+ if (!kfifo_is_empty(&tport->xmit_fifo)) {
/* Re-enable Tx FIFO interrupt */
val = rda_uart_read(port, RDA_UART_IRQ_MASK);
val |= RDA_UART_TX_DATA_NEEDED;
@@ -782,7 +777,7 @@ static void rda_uart_remove(struct platform_device *pdev)
static struct platform_driver rda_uart_platform_driver = {
.probe = rda_uart_probe,
- .remove_new = rda_uart_remove,
+ .remove = rda_uart_remove,
.driver = {
.name = "rda-uart",
.of_match_table = rda_uart_dt_matches,
diff --git a/drivers/tty/serial/rp2.c b/drivers/tty/serial/rp2.c
index 4132fcff7d4e..6d99a02dd439 100644
--- a/drivers/tty/serial/rp2.c
+++ b/drivers/tty/serial/rp2.c
@@ -577,8 +577,8 @@ static void rp2_reset_asic(struct rp2_card *card, unsigned int asic_id)
u32 clk_cfg;
writew(1, base + RP2_GLOBAL_CMD);
- readw(base + RP2_GLOBAL_CMD);
msleep(100);
+ readw(base + RP2_GLOBAL_CMD);
writel(0, base + RP2_CLK_PRESCALER);
/* TDM clock configuration */
@@ -698,7 +698,6 @@ static int rp2_probe(struct pci_dev *pdev,
const struct firmware *fw;
struct rp2_card *card;
struct rp2_uart_port *ports;
- void __iomem * const *bars;
int rc;
card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);
@@ -711,13 +710,16 @@ static int rp2_probe(struct pci_dev *pdev,
if (rc)
return rc;
- rc = pcim_iomap_regions_request_all(pdev, 0x03, DRV_NAME);
+ rc = pcim_request_all_regions(pdev, DRV_NAME);
if (rc)
return rc;
- bars = pcim_iomap_table(pdev);
- card->bar0 = bars[0];
- card->bar1 = bars[1];
+ card->bar0 = pcim_iomap(pdev, 0, 0);
+ if (!card->bar0)
+ return -ENOMEM;
+ card->bar1 = pcim_iomap(pdev, 1, 0);
+ if (!card->bar1)
+ return -ENOMEM;
card->pdev = pdev;
rp2_decode_cap(id, &card->n_ports, &card->smpte);
diff --git a/drivers/tty/serial/sa1100.c b/drivers/tty/serial/sa1100.c
index 79c794fa6545..8587ebbe1073 100644
--- a/drivers/tty/serial/sa1100.c
+++ b/drivers/tty/serial/sa1100.c
@@ -369,7 +369,7 @@ static void sa1100_shutdown(struct uart_port *port)
/*
* Stop our timer.
*/
- del_timer_sync(&sport->timer);
+ timer_delete_sync(&sport->timer);
/*
* Free the interrupt
@@ -421,7 +421,7 @@ sa1100_set_termios(struct uart_port *port, struct ktermios *termios,
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
- del_timer_sync(&sport->timer);
+ timer_delete_sync(&sport->timer);
uart_port_lock_irqsave(&sport->port, &flags);
@@ -880,7 +880,7 @@ static void sa1100_serial_remove(struct platform_device *pdev)
static struct platform_driver sa11x0_serial_driver = {
.probe = sa1100_serial_probe,
- .remove_new = sa1100_serial_remove,
+ .remove = sa1100_serial_remove,
.suspend = sa1100_serial_suspend,
.resume = sa1100_serial_resume,
.driver = {
diff --git a/drivers/tty/serial/samsung_tty.c b/drivers/tty/serial/samsung_tty.c
index a2d07e05c502..210fff7164c1 100644
--- a/drivers/tty/serial/samsung_tty.c
+++ b/drivers/tty/serial/samsung_tty.c
@@ -329,7 +329,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
{
struct s3c24xx_uart_port *ourport = args;
struct uart_port *port = &ourport->port;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
struct s3c24xx_uart_dma *dma = ourport->dma;
struct dma_tx_state state;
unsigned long flags;
@@ -348,7 +348,7 @@ static void s3c24xx_serial_tx_dma_complete(void *args)
uart_xmit_advance(port, count);
ourport->tx_in_progress = 0;
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
s3c24xx_serial_start_next_tx(ourport);
@@ -431,17 +431,15 @@ static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport)
}
static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
- unsigned int count)
+ unsigned int count, unsigned int tail)
{
- struct uart_port *port = &ourport->port;
- struct circ_buf *xmit = &port->state->xmit;
struct s3c24xx_uart_dma *dma = ourport->dma;
if (ourport->tx_mode != S3C24XX_TX_DMA)
enable_tx_dma(ourport);
dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
- dma->tx_transfer_addr = dma->tx_addr + xmit->tail;
+ dma->tx_transfer_addr = dma->tx_addr + tail;
dma_sync_single_for_device(dma->tx_chan->device->dev,
dma->tx_transfer_addr, dma->tx_size,
@@ -468,11 +466,11 @@ static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
{
struct uart_port *port = &ourport->port;
- struct circ_buf *xmit = &port->state->xmit;
- unsigned long count;
+ struct tty_port *tport = &port->state->port;
+ unsigned int count, tail;
/* Get data size up to the end of buffer */
- count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ count = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE);
if (!count) {
s3c24xx_serial_stop_tx(port);
@@ -481,16 +479,16 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
if (!ourport->dma || !ourport->dma->tx_chan ||
count < ourport->min_dma_size ||
- xmit->tail & (dma_get_cache_alignment() - 1))
+ tail & (dma_get_cache_alignment() - 1))
s3c24xx_serial_start_tx_pio(ourport);
else
- s3c24xx_serial_start_tx_dma(ourport, count);
+ s3c24xx_serial_start_tx_dma(ourport, count, tail);
}
static void s3c24xx_serial_start_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
if (!ourport->tx_enabled) {
if (port->flags & UPF_CONS_FLOW)
@@ -502,7 +500,8 @@ static void s3c24xx_serial_start_tx(struct uart_port *port)
}
if (ourport->dma && ourport->dma->tx_chan) {
- if (!uart_circ_empty(xmit) && !ourport->tx_in_progress)
+ if (!kfifo_is_empty(&tport->xmit_fifo) &&
+ !ourport->tx_in_progress)
s3c24xx_serial_start_next_tx(ourport);
}
}
@@ -551,6 +550,7 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
case TYPE_APPLE_S5L:
s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON);
s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTO_ENA, S3C2410_UCON);
+ s3c24xx_clear_bit(port, APPLE_S5L_UCON_RXTO_LEGACY_ENA, S3C2410_UCON);
break;
default:
disable_irq_nosync(ourport->rx_irq);
@@ -708,9 +708,8 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport);
-static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id)
+static irqreturn_t s3c24xx_serial_rx_chars_dma(struct s3c24xx_uart_port *ourport)
{
- struct s3c24xx_uart_port *ourport = dev_id;
struct uart_port *port = &ourport->port;
struct s3c24xx_uart_dma *dma = ourport->dma;
struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
@@ -844,9 +843,8 @@ static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
tty_flip_buffer_push(&port->state->port);
}
-static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
+static irqreturn_t s3c24xx_serial_rx_chars_pio(struct s3c24xx_uart_port *ourport)
{
- struct s3c24xx_uart_port *ourport = dev_id;
struct uart_port *port = &ourport->port;
uart_port_lock(port);
@@ -856,30 +854,29 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id)
return IRQ_HANDLED;
}
-static irqreturn_t s3c24xx_serial_rx_irq(int irq, void *dev_id)
+static irqreturn_t s3c24xx_serial_rx_irq(struct s3c24xx_uart_port *ourport)
{
- struct s3c24xx_uart_port *ourport = dev_id;
-
if (ourport->dma && ourport->dma->rx_chan)
- return s3c24xx_serial_rx_chars_dma(dev_id);
- return s3c24xx_serial_rx_chars_pio(dev_id);
+ return s3c24xx_serial_rx_chars_dma(ourport);
+ return s3c24xx_serial_rx_chars_pio(ourport);
}
static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport)
{
struct uart_port *port = &ourport->port;
- struct circ_buf *xmit = &port->state->xmit;
- int count, dma_count = 0;
+ struct tty_port *tport = &port->state->port;
+ unsigned int count, dma_count = 0, tail;
- count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ count = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE);
if (ourport->dma && ourport->dma->tx_chan &&
count >= ourport->min_dma_size) {
int align = dma_get_cache_alignment() -
- (xmit->tail & (dma_get_cache_alignment() - 1));
+ (tail & (dma_get_cache_alignment() - 1));
if (count - align >= ourport->min_dma_size) {
dma_count = count - align;
count = align;
+ tail += align;
}
}
@@ -894,7 +891,7 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport)
* stopped, disable the uart and exit
*/
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
s3c24xx_serial_stop_tx(port);
return;
}
@@ -906,30 +903,30 @@ static void s3c24xx_serial_tx_chars(struct s3c24xx_uart_port *ourport)
dma_count = 0;
}
- while (!uart_circ_empty(xmit) && count > 0) {
- if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
+ while (!(rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)) {
+ unsigned char ch;
+
+ if (!uart_fifo_get(port, &ch))
break;
- wr_reg(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
- uart_xmit_advance(port, 1);
+ wr_reg(port, S3C2410_UTXH, ch);
count--;
}
if (!count && dma_count) {
- s3c24xx_serial_start_tx_dma(ourport, dma_count);
+ s3c24xx_serial_start_tx_dma(ourport, dma_count, tail);
return;
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
s3c24xx_serial_stop_tx(port);
}
-static irqreturn_t s3c24xx_serial_tx_irq(int irq, void *id)
+static irqreturn_t s3c24xx_serial_tx_irq(struct s3c24xx_uart_port *ourport)
{
- struct s3c24xx_uart_port *ourport = id;
struct uart_port *port = &ourport->port;
uart_port_lock(port);
@@ -943,17 +940,17 @@ static irqreturn_t s3c24xx_serial_tx_irq(int irq, void *id)
/* interrupt handler for s3c64xx and later SoC's.*/
static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
{
- const struct s3c24xx_uart_port *ourport = id;
+ struct s3c24xx_uart_port *ourport = id;
const struct uart_port *port = &ourport->port;
u32 pend = rd_regl(port, S3C64XX_UINTP);
irqreturn_t ret = IRQ_HANDLED;
if (pend & S3C64XX_UINTM_RXD_MSK) {
- ret = s3c24xx_serial_rx_irq(irq, id);
+ ret = s3c24xx_serial_rx_irq(ourport);
wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_RXD_MSK);
}
if (pend & S3C64XX_UINTM_TXD_MSK) {
- ret = s3c24xx_serial_tx_irq(irq, id);
+ ret = s3c24xx_serial_tx_irq(ourport);
wr_regl(port, S3C64XX_UINTP, S3C64XX_UINTM_TXD_MSK);
}
return ret;
@@ -962,19 +959,21 @@ static irqreturn_t s3c64xx_serial_handle_irq(int irq, void *id)
/* interrupt handler for Apple SoC's.*/
static irqreturn_t apple_serial_handle_irq(int irq, void *id)
{
- const struct s3c24xx_uart_port *ourport = id;
+ struct s3c24xx_uart_port *ourport = id;
const struct uart_port *port = &ourport->port;
u32 pend = rd_regl(port, S3C2410_UTRSTAT);
irqreturn_t ret = IRQ_NONE;
- if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO)) {
+ if (pend & (APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO |
+ APPLE_S5L_UTRSTAT_RXTO_LEGACY)) {
wr_regl(port, S3C2410_UTRSTAT,
- APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO);
- ret = s3c24xx_serial_rx_irq(irq, id);
+ APPLE_S5L_UTRSTAT_RXTHRESH | APPLE_S5L_UTRSTAT_RXTO |
+ APPLE_S5L_UTRSTAT_RXTO_LEGACY);
+ ret = s3c24xx_serial_rx_irq(ourport);
}
if (pend & APPLE_S5L_UTRSTAT_TXTHRESH) {
wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_TXTHRESH);
- ret = s3c24xx_serial_tx_irq(irq, id);
+ ret = s3c24xx_serial_tx_irq(ourport);
}
return ret;
@@ -1118,7 +1117,8 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
/* TX buffer */
dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
- p->port.state->xmit.buf, UART_XMIT_SIZE,
+ p->port.state->port.xmit_buf,
+ UART_XMIT_SIZE,
DMA_TO_DEVICE);
if (dma_mapping_error(dma->tx_chan->device->dev, dma->tx_addr)) {
reason = "DMA mapping error for TX buffer";
@@ -1193,7 +1193,8 @@ static void apple_s5l_serial_shutdown(struct uart_port *port)
ucon = rd_regl(port, S3C2410_UCON);
ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK |
APPLE_S5L_UCON_RXTHRESH_ENA_MSK |
- APPLE_S5L_UCON_RXTO_ENA_MSK);
+ APPLE_S5L_UCON_RXTO_ENA_MSK |
+ APPLE_S5L_UCON_RXTO_LEGACY_ENA_MSK);
wr_regl(port, S3C2410_UCON, ucon);
wr_regl(port, S3C2410_UTRSTAT, APPLE_S5L_UTRSTAT_ALL_FLAGS);
@@ -1290,6 +1291,7 @@ static int apple_s5l_serial_startup(struct uart_port *port)
/* Enable Rx Interrupt */
s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTHRESH_ENA, S3C2410_UCON);
s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTO_ENA, S3C2410_UCON);
+ s3c24xx_set_bit(port, APPLE_S5L_UCON_RXTO_LEGACY_ENA, S3C2410_UCON);
return ret;
}
@@ -2146,13 +2148,15 @@ static int s3c24xx_serial_resume_noirq(struct device *dev)
ucon &= ~(APPLE_S5L_UCON_TXTHRESH_ENA_MSK |
APPLE_S5L_UCON_RXTHRESH_ENA_MSK |
- APPLE_S5L_UCON_RXTO_ENA_MSK);
+ APPLE_S5L_UCON_RXTO_ENA_MSK |
+ APPLE_S5L_UCON_RXTO_LEGACY_ENA_MSK);
if (ourport->tx_enabled)
ucon |= APPLE_S5L_UCON_TXTHRESH_ENA_MSK;
if (ourport->rx_enabled)
ucon |= APPLE_S5L_UCON_RXTHRESH_ENA_MSK |
- APPLE_S5L_UCON_RXTO_ENA_MSK;
+ APPLE_S5L_UCON_RXTO_ENA_MSK |
+ APPLE_S5L_UCON_RXTO_LEGACY_ENA_MSK;
wr_regl(port, S3C2410_UCON, ucon);
@@ -2494,6 +2498,12 @@ static const struct s3c24xx_serial_drv_data exynos850_serial_drv_data = {
.fifosize = { 256, 64, 64, 64 },
};
+static const struct s3c24xx_serial_drv_data exynos8895_serial_drv_data = {
+ EXYNOS_COMMON_SERIAL_DRV_DATA,
+ /* samsung,uart-fifosize must be specified in the device tree. */
+ .fifosize = { 0 },
+};
+
static const struct s3c24xx_serial_drv_data gs101_serial_drv_data = {
.info = {
.name = "Google GS101 UART",
@@ -2524,12 +2534,14 @@ static const struct s3c24xx_serial_drv_data gs101_serial_drv_data = {
#define EXYNOS4210_SERIAL_DRV_DATA (&exynos4210_serial_drv_data)
#define EXYNOS5433_SERIAL_DRV_DATA (&exynos5433_serial_drv_data)
#define EXYNOS850_SERIAL_DRV_DATA (&exynos850_serial_drv_data)
+#define EXYNOS8895_SERIAL_DRV_DATA (&exynos8895_serial_drv_data)
#define GS101_SERIAL_DRV_DATA (&gs101_serial_drv_data)
#else
#define EXYNOS4210_SERIAL_DRV_DATA NULL
#define EXYNOS5433_SERIAL_DRV_DATA NULL
#define EXYNOS850_SERIAL_DRV_DATA NULL
+#define EXYNOS8895_SERIAL_DRV_DATA NULL
#define GS101_SERIAL_DRV_DATA NULL
#endif
@@ -2539,7 +2551,7 @@ static const struct s3c24xx_serial_drv_data s5l_serial_drv_data = {
.name = "Apple S5L UART",
.type = TYPE_APPLE_S5L,
.port_type = PORT_8250,
- .iotype = UPIO_MEM,
+ .iotype = UPIO_MEM32,
.fifosize = 16,
.rx_fifomask = S3C2410_UFSTAT_RXMASK,
.rx_fifoshift = S3C2410_UFSTAT_RXSHIFT,
@@ -2619,6 +2631,9 @@ static const struct platform_device_id s3c24xx_serial_driver_ids[] = {
}, {
.name = "gs101-uart",
.driver_data = (kernel_ulong_t)GS101_SERIAL_DRV_DATA,
+ }, {
+ .name = "exynos8895-uart",
+ .driver_data = (kernel_ulong_t)EXYNOS8895_SERIAL_DRV_DATA,
},
{ },
};
@@ -2642,6 +2657,8 @@ static const struct of_device_id s3c24xx_uart_dt_match[] = {
.data = ARTPEC8_SERIAL_DRV_DATA },
{ .compatible = "google,gs101-uart",
.data = GS101_SERIAL_DRV_DATA },
+ { .compatible = "samsung,exynos8895-uart",
+ .data = EXYNOS8895_SERIAL_DRV_DATA },
{},
};
MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
@@ -2649,7 +2666,7 @@ MODULE_DEVICE_TABLE(of, s3c24xx_uart_dt_match);
static struct platform_driver samsung_serial_driver = {
.probe = s3c24xx_serial_probe,
- .remove_new = s3c24xx_serial_remove,
+ .remove = s3c24xx_serial_remove,
.id_table = s3c24xx_serial_driver_ids,
.driver = {
.name = "samsung-uart",
@@ -2825,6 +2842,9 @@ OF_EARLYCON_DECLARE(gs101, "google,gs101-uart", gs101_early_console_setup);
static int __init apple_s5l_early_console_setup(struct earlycon_device *device,
const char *opt)
{
+ /* Apple A7-A11 requires MMIO32 register accesses. */
+ device->port.iotype = UPIO_MEM32;
+
/* Close enough to S3C2410 for earlycon... */
device->port.private_data = &s3c2410_early_console_data;
diff --git a/drivers/tty/serial/sb1250-duart.c b/drivers/tty/serial/sb1250-duart.c
index dbec29d9a6c3..b4e1b90e5960 100644
--- a/drivers/tty/serial/sb1250-duart.c
+++ b/drivers/tty/serial/sb1250-duart.c
@@ -382,7 +382,8 @@ static void sbd_receive_chars(struct sbd_port *sport)
static void sbd_transmit_chars(struct sbd_port *sport)
{
struct uart_port *uport = &sport->port;
- struct circ_buf *xmit = &sport->port.state->xmit;
+ struct tty_port *tport = &sport->port.state->port;
+ unsigned char ch;
unsigned int mask;
int stop_tx;
@@ -395,19 +396,19 @@ static void sbd_transmit_chars(struct sbd_port *sport)
}
/* If nothing to do or stopped or hardware stopped. */
- stop_tx = (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port));
+ stop_tx = uart_tx_stopped(&sport->port) ||
+ !uart_fifo_get(&sport->port, &ch);
/* Send char. */
if (!stop_tx) {
- write_sbdchn(sport, R_DUART_TX_HOLD, xmit->buf[xmit->tail]);
- uart_xmit_advance(&sport->port, 1);
+ write_sbdchn(sport, R_DUART_TX_HOLD, ch);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&sport->port);
}
/* Are we are done? */
- if (stop_tx || uart_circ_empty(xmit)) {
+ if (stop_tx || kfifo_is_empty(&tport->xmit_fifo)) {
/* Disable tx interrupts. */
mask = read_sbdshr(sport, R_DUART_IMRREG((uport->line) % 2));
mask &= ~M_DUART_IMR_TX;
diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c
index 929206a9a6e1..560f45ed19ae 100644
--- a/drivers/tty/serial/sc16is7xx.c
+++ b/drivers/tty/serial/sc16is7xx.c
@@ -1,35 +1,40 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * SC16IS7xx tty serial driver - Copyright (C) 2014 GridPoint
- * Author: Jon Ringle <jringle@gridpoint.com>
+ * SC16IS7xx tty serial driver - common code
*
- * Based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
+ * Copyright (C) 2014 GridPoint
+ * Author: Jon Ringle <jringle@gridpoint.com>
+ * Based on max310x.c, by Alexander Shiyan <shc_work@mail.ru>
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#undef DEFAULT_SYMBOL_NAMESPACE
+#define DEFAULT_SYMBOL_NAMESPACE "SERIAL_NXP_SC16IS7XX"
-#include <linux/bitops.h>
+#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
-#include <linux/i2c.h>
+#include <linux/idr.h>
+#include <linux/kthread.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
#include <linux/regmap.h>
+#include <linux/sched.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
+#include <linux/string.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <linux/spi/spi.h>
#include <linux/uaccess.h>
#include <linux/units.h>
-#include <uapi/linux/sched/types.h>
-#define SC16IS7XX_NAME "sc16is7xx"
+#include "sc16is7xx.h"
+
#define SC16IS7XX_MAX_DEVS 8
-#define SC16IS7XX_MAX_PORTS 2 /* Maximum number of UART ports per IC. */
/* SC16IS7XX register definitions */
#define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */
@@ -74,52 +79,52 @@
#define SC16IS7XX_XOFF2_REG (0x07) /* Xoff2 word */
/* IER register bits */
-#define SC16IS7XX_IER_RDI_BIT (1 << 0) /* Enable RX data interrupt */
-#define SC16IS7XX_IER_THRI_BIT (1 << 1) /* Enable TX holding register
+#define SC16IS7XX_IER_RDI_BIT BIT(0) /* Enable RX data interrupt */
+#define SC16IS7XX_IER_THRI_BIT BIT(1) /* Enable TX holding register
* interrupt */
-#define SC16IS7XX_IER_RLSI_BIT (1 << 2) /* Enable RX line status
+#define SC16IS7XX_IER_RLSI_BIT BIT(2) /* Enable RX line status
* interrupt */
-#define SC16IS7XX_IER_MSI_BIT (1 << 3) /* Enable Modem status
+#define SC16IS7XX_IER_MSI_BIT BIT(3) /* Enable Modem status
* interrupt */
/* IER register bits - write only if (EFR[4] == 1) */
-#define SC16IS7XX_IER_SLEEP_BIT (1 << 4) /* Enable Sleep mode */
-#define SC16IS7XX_IER_XOFFI_BIT (1 << 5) /* Enable Xoff interrupt */
-#define SC16IS7XX_IER_RTSI_BIT (1 << 6) /* Enable nRTS interrupt */
-#define SC16IS7XX_IER_CTSI_BIT (1 << 7) /* Enable nCTS interrupt */
+#define SC16IS7XX_IER_SLEEP_BIT BIT(4) /* Enable Sleep mode */
+#define SC16IS7XX_IER_XOFFI_BIT BIT(5) /* Enable Xoff interrupt */
+#define SC16IS7XX_IER_RTSI_BIT BIT(6) /* Enable nRTS interrupt */
+#define SC16IS7XX_IER_CTSI_BIT BIT(7) /* Enable nCTS interrupt */
/* FCR register bits */
-#define SC16IS7XX_FCR_FIFO_BIT (1 << 0) /* Enable FIFO */
-#define SC16IS7XX_FCR_RXRESET_BIT (1 << 1) /* Reset RX FIFO */
-#define SC16IS7XX_FCR_TXRESET_BIT (1 << 2) /* Reset TX FIFO */
-#define SC16IS7XX_FCR_RXLVLL_BIT (1 << 6) /* RX Trigger level LSB */
-#define SC16IS7XX_FCR_RXLVLH_BIT (1 << 7) /* RX Trigger level MSB */
+#define SC16IS7XX_FCR_FIFO_BIT BIT(0) /* Enable FIFO */
+#define SC16IS7XX_FCR_RXRESET_BIT BIT(1) /* Reset RX FIFO */
+#define SC16IS7XX_FCR_TXRESET_BIT BIT(2) /* Reset TX FIFO */
+#define SC16IS7XX_FCR_RXLVLL_BIT BIT(6) /* RX Trigger level LSB */
+#define SC16IS7XX_FCR_RXLVLH_BIT BIT(7) /* RX Trigger level MSB */
/* FCR register bits - write only if (EFR[4] == 1) */
-#define SC16IS7XX_FCR_TXLVLL_BIT (1 << 4) /* TX Trigger level LSB */
-#define SC16IS7XX_FCR_TXLVLH_BIT (1 << 5) /* TX Trigger level MSB */
+#define SC16IS7XX_FCR_TXLVLL_BIT BIT(4) /* TX Trigger level LSB */
+#define SC16IS7XX_FCR_TXLVLH_BIT BIT(5) /* TX Trigger level MSB */
/* IIR register bits */
-#define SC16IS7XX_IIR_NO_INT_BIT (1 << 0) /* No interrupts pending */
-#define SC16IS7XX_IIR_ID_MASK 0x3e /* Mask for the interrupt ID */
-#define SC16IS7XX_IIR_THRI_SRC 0x02 /* TX holding register empty */
-#define SC16IS7XX_IIR_RDI_SRC 0x04 /* RX data interrupt */
-#define SC16IS7XX_IIR_RLSE_SRC 0x06 /* RX line status error */
-#define SC16IS7XX_IIR_RTOI_SRC 0x0c /* RX time-out interrupt */
-#define SC16IS7XX_IIR_MSI_SRC 0x00 /* Modem status interrupt
- * - only on 75x/76x
- */
-#define SC16IS7XX_IIR_INPIN_SRC 0x30 /* Input pin change of state
- * - only on 75x/76x
- */
-#define SC16IS7XX_IIR_XOFFI_SRC 0x10 /* Received Xoff */
-#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state
- * from active (LOW)
- * to inactive (HIGH)
- */
+#define SC16IS7XX_IIR_NO_INT_BIT 0x01 /* No interrupts pending */
+#define SC16IS7XX_IIR_ID_MASK GENMASK(5, 1) /* Mask for the interrupt ID */
+#define SC16IS7XX_IIR_THRI_SRC 0x02 /* TX holding register empty */
+#define SC16IS7XX_IIR_RDI_SRC 0x04 /* RX data interrupt */
+#define SC16IS7XX_IIR_RLSE_SRC 0x06 /* RX line status error */
+#define SC16IS7XX_IIR_RTOI_SRC 0x0c /* RX time-out interrupt */
+#define SC16IS7XX_IIR_MSI_SRC 0x00 /* Modem status interrupt
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_IIR_INPIN_SRC 0x30 /* Input pin change of state
+ * - only on 75x/76x
+ */
+#define SC16IS7XX_IIR_XOFFI_SRC 0x10 /* Received Xoff */
+#define SC16IS7XX_IIR_CTSRTS_SRC 0x20 /* nCTS,nRTS change of state
+ * from active (LOW)
+ * to inactive (HIGH)
+ */
/* LCR register bits */
-#define SC16IS7XX_LCR_LENGTH0_BIT (1 << 0) /* Word length bit 0 */
-#define SC16IS7XX_LCR_LENGTH1_BIT (1 << 1) /* Word length bit 1
+#define SC16IS7XX_LCR_LENGTH0_BIT BIT(0) /* Word length bit 0 */
+#define SC16IS7XX_LCR_LENGTH1_BIT BIT(1) /* Word length bit 1
*
* Word length bits table:
* 00 -> 5 bit words
@@ -127,7 +132,7 @@
* 10 -> 7 bit words
* 11 -> 8 bit words
*/
-#define SC16IS7XX_LCR_STOPLEN_BIT (1 << 2) /* STOP length bit
+#define SC16IS7XX_LCR_STOPLEN_BIT BIT(2) /* STOP length bit
*
* STOP length bit table:
* 0 -> 1 stop bit
@@ -135,11 +140,11 @@
* word length is 5,
* 2 stop bits otherwise
*/
-#define SC16IS7XX_LCR_PARITY_BIT (1 << 3) /* Parity bit enable */
-#define SC16IS7XX_LCR_EVENPARITY_BIT (1 << 4) /* Even parity bit enable */
-#define SC16IS7XX_LCR_FORCEPARITY_BIT (1 << 5) /* 9-bit multidrop parity */
-#define SC16IS7XX_LCR_TXBREAK_BIT (1 << 6) /* TX break enable */
-#define SC16IS7XX_LCR_DLAB_BIT (1 << 7) /* Divisor Latch enable */
+#define SC16IS7XX_LCR_PARITY_BIT BIT(3) /* Parity bit enable */
+#define SC16IS7XX_LCR_EVENPARITY_BIT BIT(4) /* Even parity bit enable */
+#define SC16IS7XX_LCR_FORCEPARITY_BIT BIT(5) /* 9-bit multidrop parity */
+#define SC16IS7XX_LCR_TXBREAK_BIT BIT(6) /* TX break enable */
+#define SC16IS7XX_LCR_DLAB_BIT BIT(7) /* Divisor Latch enable */
#define SC16IS7XX_LCR_WORD_LEN_5 (0x00)
#define SC16IS7XX_LCR_WORD_LEN_6 (0x01)
#define SC16IS7XX_LCR_WORD_LEN_7 (0x02)
@@ -150,61 +155,65 @@
* reg set */
/* MCR register bits */
-#define SC16IS7XX_MCR_DTR_BIT (1 << 0) /* DTR complement
+#define SC16IS7XX_MCR_DTR_BIT BIT(0) /* DTR complement
* - only on 75x/76x
*/
-#define SC16IS7XX_MCR_RTS_BIT (1 << 1) /* RTS complement */
-#define SC16IS7XX_MCR_TCRTLR_BIT (1 << 2) /* TCR/TLR register enable */
-#define SC16IS7XX_MCR_LOOP_BIT (1 << 4) /* Enable loopback test mode */
-#define SC16IS7XX_MCR_XONANY_BIT (1 << 5) /* Enable Xon Any
+#define SC16IS7XX_MCR_RTS_BIT BIT(1) /* RTS complement */
+#define SC16IS7XX_MCR_TCRTLR_BIT BIT(2) /* TCR/TLR register enable */
+#define SC16IS7XX_MCR_LOOP_BIT BIT(4) /* Enable loopback test mode */
+#define SC16IS7XX_MCR_XONANY_BIT BIT(5) /* Enable Xon Any
* - write enabled
* if (EFR[4] == 1)
*/
-#define SC16IS7XX_MCR_IRDA_BIT (1 << 6) /* Enable IrDA mode
+#define SC16IS7XX_MCR_IRDA_BIT BIT(6) /* Enable IrDA mode
* - write enabled
* if (EFR[4] == 1)
*/
-#define SC16IS7XX_MCR_CLKSEL_BIT (1 << 7) /* Divide clock by 4
+#define SC16IS7XX_MCR_CLKSEL_BIT BIT(7) /* Divide clock by 4
* - write enabled
* if (EFR[4] == 1)
*/
/* LSR register bits */
-#define SC16IS7XX_LSR_DR_BIT (1 << 0) /* Receiver data ready */
-#define SC16IS7XX_LSR_OE_BIT (1 << 1) /* Overrun Error */
-#define SC16IS7XX_LSR_PE_BIT (1 << 2) /* Parity Error */
-#define SC16IS7XX_LSR_FE_BIT (1 << 3) /* Frame Error */
-#define SC16IS7XX_LSR_BI_BIT (1 << 4) /* Break Interrupt */
-#define SC16IS7XX_LSR_BRK_ERROR_MASK 0x1E /* BI, FE, PE, OE bits */
-#define SC16IS7XX_LSR_THRE_BIT (1 << 5) /* TX holding register empty */
-#define SC16IS7XX_LSR_TEMT_BIT (1 << 6) /* Transmitter empty */
-#define SC16IS7XX_LSR_FIFOE_BIT (1 << 7) /* Fifo Error */
+#define SC16IS7XX_LSR_DR_BIT BIT(0) /* Receiver data ready */
+#define SC16IS7XX_LSR_OE_BIT BIT(1) /* Overrun Error */
+#define SC16IS7XX_LSR_PE_BIT BIT(2) /* Parity Error */
+#define SC16IS7XX_LSR_FE_BIT BIT(3) /* Frame Error */
+#define SC16IS7XX_LSR_BI_BIT BIT(4) /* Break Interrupt */
+#define SC16IS7XX_LSR_BRK_ERROR_MASK \
+ (SC16IS7XX_LSR_OE_BIT | \
+ SC16IS7XX_LSR_PE_BIT | \
+ SC16IS7XX_LSR_FE_BIT | \
+ SC16IS7XX_LSR_BI_BIT)
+
+#define SC16IS7XX_LSR_THRE_BIT BIT(5) /* TX holding register empty */
+#define SC16IS7XX_LSR_TEMT_BIT BIT(6) /* Transmitter empty */
+#define SC16IS7XX_LSR_FIFOE_BIT BIT(7) /* Fifo Error */
/* MSR register bits */
-#define SC16IS7XX_MSR_DCTS_BIT (1 << 0) /* Delta CTS Clear To Send */
-#define SC16IS7XX_MSR_DDSR_BIT (1 << 1) /* Delta DSR Data Set Ready
+#define SC16IS7XX_MSR_DCTS_BIT BIT(0) /* Delta CTS Clear To Send */
+#define SC16IS7XX_MSR_DDSR_BIT BIT(1) /* Delta DSR Data Set Ready
* or (IO4)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_DRI_BIT (1 << 2) /* Delta RI Ring Indicator
+#define SC16IS7XX_MSR_DRI_BIT BIT(2) /* Delta RI Ring Indicator
* or (IO7)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_DCD_BIT (1 << 3) /* Delta CD Carrier Detect
+#define SC16IS7XX_MSR_DCD_BIT BIT(3) /* Delta CD Carrier Detect
* or (IO6)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_CTS_BIT (1 << 4) /* CTS */
-#define SC16IS7XX_MSR_DSR_BIT (1 << 5) /* DSR (IO4)
+#define SC16IS7XX_MSR_CTS_BIT BIT(4) /* CTS */
+#define SC16IS7XX_MSR_DSR_BIT BIT(5) /* DSR (IO4)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_RI_BIT (1 << 6) /* RI (IO7)
+#define SC16IS7XX_MSR_RI_BIT BIT(6) /* RI (IO7)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_CD_BIT (1 << 7) /* CD (IO6)
+#define SC16IS7XX_MSR_CD_BIT BIT(7) /* CD (IO6)
* - only on 75x/76x
*/
-#define SC16IS7XX_MSR_DELTA_MASK 0x0F /* Any of the delta bits! */
/*
* TCR register bits
@@ -237,19 +246,19 @@
#define SC16IS7XX_TLR_RX_TRIGGER(words) ((((words) / 4) & 0x0f) << 4)
/* IOControl register bits (Only 75x/76x) */
-#define SC16IS7XX_IOCONTROL_LATCH_BIT (1 << 0) /* Enable input latching */
-#define SC16IS7XX_IOCONTROL_MODEM_A_BIT (1 << 1) /* Enable GPIO[7:4] as modem A pins */
-#define SC16IS7XX_IOCONTROL_MODEM_B_BIT (1 << 2) /* Enable GPIO[3:0] as modem B pins */
-#define SC16IS7XX_IOCONTROL_SRESET_BIT (1 << 3) /* Software Reset */
+#define SC16IS7XX_IOCONTROL_LATCH_BIT BIT(0) /* Enable input latching */
+#define SC16IS7XX_IOCONTROL_MODEM_A_BIT BIT(1) /* Enable GPIO[7:4] as modem A pins */
+#define SC16IS7XX_IOCONTROL_MODEM_B_BIT BIT(2) /* Enable GPIO[3:0] as modem B pins */
+#define SC16IS7XX_IOCONTROL_SRESET_BIT BIT(3) /* Software Reset */
/* EFCR register bits */
-#define SC16IS7XX_EFCR_9BIT_MODE_BIT (1 << 0) /* Enable 9-bit or Multidrop
+#define SC16IS7XX_EFCR_9BIT_MODE_BIT BIT(0) /* Enable 9-bit or Multidrop
* mode (RS485) */
-#define SC16IS7XX_EFCR_RXDISABLE_BIT (1 << 1) /* Disable receiver */
-#define SC16IS7XX_EFCR_TXDISABLE_BIT (1 << 2) /* Disable transmitter */
-#define SC16IS7XX_EFCR_AUTO_RS485_BIT (1 << 4) /* Auto RS485 RTS direction */
-#define SC16IS7XX_EFCR_RTS_INVERT_BIT (1 << 5) /* RTS output inversion */
-#define SC16IS7XX_EFCR_IRDA_MODE_BIT (1 << 7) /* IrDA mode
+#define SC16IS7XX_EFCR_RXDISABLE_BIT BIT(1) /* Disable receiver */
+#define SC16IS7XX_EFCR_TXDISABLE_BIT BIT(2) /* Disable transmitter */
+#define SC16IS7XX_EFCR_AUTO_RS485_BIT BIT(4) /* Auto RS485 RTS direction */
+#define SC16IS7XX_EFCR_RTS_INVERT_BIT BIT(5) /* RTS output inversion */
+#define SC16IS7XX_EFCR_IRDA_MODE_BIT BIT(7) /* IrDA mode
* 0 = rate upto 115.2 kbit/s
* - Only 75x/76x
* 1 = rate upto 1.152 Mbit/s
@@ -257,16 +266,16 @@
*/
/* EFR register bits */
-#define SC16IS7XX_EFR_AUTORTS_BIT (1 << 6) /* Auto RTS flow ctrl enable */
-#define SC16IS7XX_EFR_AUTOCTS_BIT (1 << 7) /* Auto CTS flow ctrl enable */
-#define SC16IS7XX_EFR_XOFF2_DETECT_BIT (1 << 5) /* Enable Xoff2 detection */
-#define SC16IS7XX_EFR_ENABLE_BIT (1 << 4) /* Enable enhanced functions
+#define SC16IS7XX_EFR_AUTORTS_BIT BIT(6) /* Auto RTS flow ctrl enable */
+#define SC16IS7XX_EFR_AUTOCTS_BIT BIT(7) /* Auto CTS flow ctrl enable */
+#define SC16IS7XX_EFR_XOFF2_DETECT_BIT BIT(5) /* Enable Xoff2 detection */
+#define SC16IS7XX_EFR_ENABLE_BIT BIT(4) /* Enable enhanced functions
* and writing to IER[7:4],
* FCR[5:4], MCR[7:5]
*/
-#define SC16IS7XX_EFR_SWFLOW3_BIT (1 << 3) /* SWFLOW bit 3 */
-#define SC16IS7XX_EFR_SWFLOW2_BIT (1 << 2) /* SWFLOW bit 2
- *
+#define SC16IS7XX_EFR_SWFLOW3_BIT BIT(3)
+#define SC16IS7XX_EFR_SWFLOW2_BIT BIT(2)
+ /*
* SWFLOW bits 3 & 2 table:
* 00 -> no transmitter flow
* control
@@ -278,10 +287,10 @@
* XON1, XON2, XOFF1 and
* XOFF2
*/
-#define SC16IS7XX_EFR_SWFLOW1_BIT (1 << 1) /* SWFLOW bit 2 */
-#define SC16IS7XX_EFR_SWFLOW0_BIT (1 << 0) /* SWFLOW bit 3
- *
- * SWFLOW bits 3 & 2 table:
+#define SC16IS7XX_EFR_SWFLOW1_BIT BIT(1)
+#define SC16IS7XX_EFR_SWFLOW0_BIT BIT(0)
+ /*
+ * SWFLOW bits 1 & 0 table:
* 00 -> no received flow
* control
* 01 -> receiver compares
@@ -302,19 +311,13 @@
/* Misc definitions */
-#define SC16IS7XX_SPI_READ_BIT BIT(7)
#define SC16IS7XX_FIFO_SIZE (64)
#define SC16IS7XX_GPIOS_PER_BANK 4
-struct sc16is7xx_devtype {
- char name[10];
- int nr_gpio;
- int nr_uart;
-};
-
-#define SC16IS7XX_RECONF_MD (1 << 0)
-#define SC16IS7XX_RECONF_IER (1 << 1)
-#define SC16IS7XX_RECONF_RS485 (1 << 2)
+#define SC16IS7XX_POLL_PERIOD_MS 10
+#define SC16IS7XX_RECONF_MD BIT(0)
+#define SC16IS7XX_RECONF_IER BIT(1)
+#define SC16IS7XX_RECONF_RS485 BIT(2)
struct sc16is7xx_one_config {
unsigned int flags;
@@ -330,6 +333,7 @@ struct sc16is7xx_one {
struct kthread_work reg_work;
struct kthread_delayed_work ms_work;
struct sc16is7xx_one_config config;
+ unsigned char buf[SC16IS7XX_FIFO_SIZE]; /* Rx buffer. */
unsigned int old_mctrl;
u8 old_lcr; /* Value before EFR access. */
bool irda_mode;
@@ -343,13 +347,14 @@ struct sc16is7xx_port {
unsigned long gpio_valid_mask;
#endif
u8 mctrl_mask;
- unsigned char buf[SC16IS7XX_FIFO_SIZE];
struct kthread_worker kworker;
struct task_struct *kworker_task;
+ struct kthread_delayed_work poll_work;
+ bool polling;
struct sc16is7xx_one p[];
};
-static DECLARE_BITMAP(sc16is7xx_lines, SC16IS7XX_MAX_DEVS);
+static DEFINE_IDA(sc16is7xx_lines);
static struct uart_driver sc16is7xx_uart = {
.owner = THIS_MODULE,
@@ -492,35 +497,40 @@ static void sc16is7xx_stop_rx(struct uart_port *port)
sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT);
}
-static const struct sc16is7xx_devtype sc16is74x_devtype = {
+const struct sc16is7xx_devtype sc16is74x_devtype = {
.name = "SC16IS74X",
.nr_gpio = 0,
.nr_uart = 1,
};
+EXPORT_SYMBOL_GPL(sc16is74x_devtype);
-static const struct sc16is7xx_devtype sc16is750_devtype = {
+const struct sc16is7xx_devtype sc16is750_devtype = {
.name = "SC16IS750",
.nr_gpio = 8,
.nr_uart = 1,
};
+EXPORT_SYMBOL_GPL(sc16is750_devtype);
-static const struct sc16is7xx_devtype sc16is752_devtype = {
+const struct sc16is7xx_devtype sc16is752_devtype = {
.name = "SC16IS752",
.nr_gpio = 8,
.nr_uart = 2,
};
+EXPORT_SYMBOL_GPL(sc16is752_devtype);
-static const struct sc16is7xx_devtype sc16is760_devtype = {
+const struct sc16is7xx_devtype sc16is760_devtype = {
.name = "SC16IS760",
.nr_gpio = 8,
.nr_uart = 1,
};
+EXPORT_SYMBOL_GPL(sc16is760_devtype);
-static const struct sc16is7xx_devtype sc16is762_devtype = {
+const struct sc16is7xx_devtype sc16is762_devtype = {
.name = "SC16IS762",
.nr_gpio = 8,
.nr_uart = 2,
};
+EXPORT_SYMBOL_GPL(sc16is762_devtype);
static bool sc16is7xx_regmap_volatile(struct device *dev, unsigned int reg)
{
@@ -554,16 +564,28 @@ static bool sc16is7xx_regmap_noinc(struct device *dev, unsigned int reg)
return reg == SC16IS7XX_RHR_REG;
}
+/*
+ * Configure programmable baud rate generator (divisor) according to the
+ * desired baud rate.
+ *
+ * From the datasheet, the divisor is computed according to:
+ *
+ * XTAL1 input frequency
+ * -----------------------
+ * prescaler
+ * divisor = ---------------------------
+ * baud-rate x sampling-rate
+ */
static int sc16is7xx_set_baud(struct uart_port *port, int baud)
{
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
u8 lcr;
- u8 prescaler = 0;
+ unsigned int prescaler = 1;
unsigned long clk = port->uartclk, div = clk / 16 / baud;
if (div >= BIT(16)) {
- prescaler = SC16IS7XX_MCR_CLKSEL_BIT;
- div /= 4;
+ prescaler = 4;
+ div /= prescaler;
}
/* Enable enhanced features */
@@ -573,9 +595,12 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
SC16IS7XX_EFR_ENABLE_BIT);
sc16is7xx_efr_unlock(port);
+ /* If bit MCR_CLKSEL is set, the divide by 4 prescaler is activated. */
sc16is7xx_port_update(port, SC16IS7XX_MCR_REG,
SC16IS7XX_MCR_CLKSEL_BIT,
- prescaler);
+ prescaler == 1 ? 0 : SC16IS7XX_MCR_CLKSEL_BIT);
+
+ mutex_lock(&one->efr_lock);
/* Backup LCR and access special register set (DLL/DLH) */
lcr = sc16is7xx_port_read(port, SC16IS7XX_LCR_REG);
@@ -591,24 +616,26 @@ static int sc16is7xx_set_baud(struct uart_port *port, int baud)
/* Restore LCR and access to general register set */
sc16is7xx_port_write(port, SC16IS7XX_LCR_REG, lcr);
- return DIV_ROUND_CLOSEST(clk / 16, div);
+ mutex_unlock(&one->efr_lock);
+
+ return DIV_ROUND_CLOSEST((clk / prescaler) / 16, div);
}
static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
unsigned int iir)
{
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
+ struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
unsigned int lsr = 0, bytes_read, i;
bool read_lsr = (iir == SC16IS7XX_IIR_RLSE_SRC) ? true : false;
u8 ch, flag;
- if (unlikely(rxlen >= sizeof(s->buf))) {
+ if (unlikely(rxlen >= sizeof(one->buf))) {
dev_warn_ratelimited(port->dev,
"ttySC%i: Possible RX FIFO overrun: %d\n",
port->line, rxlen);
port->icount.buf_overrun++;
/* Ensure sanity of RX level */
- rxlen = sizeof(s->buf);
+ rxlen = sizeof(one->buf);
}
while (rxlen) {
@@ -621,10 +648,10 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
lsr = 0;
if (read_lsr) {
- s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG);
+ one->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG);
bytes_read = 1;
} else {
- sc16is7xx_fifo_read(port, s->buf, rxlen);
+ sc16is7xx_fifo_read(port, one->buf, rxlen);
bytes_read = rxlen;
}
@@ -657,7 +684,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
}
for (i = 0; i < bytes_read; ++i) {
- ch = s->buf[i];
+ ch = one->buf[i];
if (uart_handle_sysrq_char(port, ch))
continue;
@@ -675,10 +702,10 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen,
static void sc16is7xx_handle_tx(struct uart_port *port)
{
- struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
- struct circ_buf *xmit = &port->state->xmit;
- unsigned int txlen, to_send, i;
+ struct tty_port *tport = &port->state->port;
unsigned long flags;
+ unsigned int txlen;
+ unsigned char *tail;
if (unlikely(port->x_char)) {
sc16is7xx_port_write(port, SC16IS7XX_THR_REG, port->x_char);
@@ -687,40 +714,31 @@ static void sc16is7xx_handle_tx(struct uart_port *port)
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
uart_port_lock_irqsave(port, &flags);
sc16is7xx_stop_tx(port);
uart_port_unlock_irqrestore(port, flags);
return;
}
- /* Get length of data pending in circular buffer */
- to_send = uart_circ_chars_pending(xmit);
- if (likely(to_send)) {
- /* Limit to space available in TX FIFO */
- txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG);
- if (txlen > SC16IS7XX_FIFO_SIZE) {
- dev_err_ratelimited(port->dev,
- "chip reports %d free bytes in TX fifo, but it only has %d",
- txlen, SC16IS7XX_FIFO_SIZE);
- txlen = 0;
- }
- to_send = (to_send > txlen) ? txlen : to_send;
-
- /* Convert to linear buffer */
- for (i = 0; i < to_send; ++i) {
- s->buf[i] = xmit->buf[xmit->tail];
- uart_xmit_advance(port, 1);
- }
-
- sc16is7xx_fifo_write(port, s->buf, to_send);
+ /* Limit to space available in TX FIFO */
+ txlen = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG);
+ if (txlen > SC16IS7XX_FIFO_SIZE) {
+ dev_err_ratelimited(port->dev,
+ "chip reports %d free bytes in TX fifo, but it only has %d",
+ txlen, SC16IS7XX_FIFO_SIZE);
+ txlen = 0;
}
+ txlen = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail, txlen);
+ sc16is7xx_fifo_write(port, tail, txlen);
+ uart_xmit_advance(port, txlen);
+
uart_port_lock_irqsave(port, &flags);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
sc16is7xx_stop_tx(port);
else
sc16is7xx_ier_set(port, SC16IS7XX_IER_THRI_BIT);
@@ -846,6 +864,18 @@ static irqreturn_t sc16is7xx_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void sc16is7xx_poll_proc(struct kthread_work *ws)
+{
+ struct sc16is7xx_port *s = container_of(ws, struct sc16is7xx_port, poll_work.work);
+
+ /* Reuse standard IRQ handler. Interrupt ID is unused in this context. */
+ sc16is7xx_irq(0, s);
+
+ /* Setup delay based on SC16IS7XX_POLL_PERIOD_MS */
+ kthread_queue_delayed_work(&s->kworker, &s->poll_work,
+ msecs_to_jiffies(SC16IS7XX_POLL_PERIOD_MS));
+}
+
static void sc16is7xx_tx_proc(struct kthread_work *ws)
{
struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port);
@@ -1134,6 +1164,7 @@ static int sc16is7xx_config_rs485(struct uart_port *port, struct ktermios *termi
static int sc16is7xx_startup(struct uart_port *port)
{
struct sc16is7xx_one *one = to_sc16is7xx_one(port, port);
+ struct sc16is7xx_port *s = dev_get_drvdata(port->dev);
unsigned int val;
unsigned long flags;
@@ -1196,6 +1227,10 @@ static int sc16is7xx_startup(struct uart_port *port)
sc16is7xx_enable_ms(port);
uart_port_unlock_irqrestore(port, flags);
+ if (s->polling)
+ kthread_queue_delayed_work(&s->kworker, &s->poll_work,
+ msecs_to_jiffies(SC16IS7XX_POLL_PERIOD_MS));
+
return 0;
}
@@ -1217,6 +1252,9 @@ static void sc16is7xx_shutdown(struct uart_port *port)
sc16is7xx_power(port, 0);
+ if (s->polling)
+ kthread_cancel_delayed_work_sync(&s->poll_work);
+
kthread_flush_worker(&s->kworker);
}
@@ -1458,20 +1496,43 @@ static int sc16is7xx_setup_mctrl_ports(struct sc16is7xx_port *s,
}
static const struct serial_rs485 sc16is7xx_rs485_supported = {
- .flags = SER_RS485_ENABLED | SER_RS485_RTS_AFTER_SEND,
+ .flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
.delay_rts_before_send = 1,
.delay_rts_after_send = 1, /* Not supported but keep returning -EINVAL */
};
-static int sc16is7xx_probe(struct device *dev,
- const struct sc16is7xx_devtype *devtype,
- struct regmap *regmaps[], int irq)
+/* Reset device, purging any pending irq / data */
+static int sc16is7xx_reset(struct device *dev, struct regmap *regmap)
+{
+ struct gpio_desc *reset_gpio;
+
+ /* Assert reset GPIO if defined and valid. */
+ reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(reset_gpio), "Failed to get reset GPIO\n");
+
+ if (reset_gpio) {
+ /* The minimum reset pulse width is 3 us. */
+ fsleep(5);
+ gpiod_set_value_cansleep(reset_gpio, 0); /* Deassert GPIO */
+ } else {
+ /* Software reset */
+ regmap_write(regmap, SC16IS7XX_IOCONTROL_REG,
+ SC16IS7XX_IOCONTROL_SRESET_BIT);
+ }
+
+ return 0;
+}
+
+int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
+ struct regmap *regmaps[], int irq)
{
unsigned long freq = 0, *pfreq = dev_get_platdata(dev);
unsigned int val;
u32 uartclk = 0;
int i, ret;
struct sc16is7xx_port *s;
+ bool port_registered[SC16IS7XX_MAX_PORTS];
for (i = 0; i < devtype->nr_uart; i++)
if (IS_ERR(regmaps[i]))
@@ -1500,6 +1561,11 @@ static int sc16is7xx_probe(struct device *dev,
/* Always ask for fixed clock rate from a property. */
device_property_read_u32(dev, "clock-frequency", &uartclk);
+ s->polling = (irq <= 0);
+ if (s->polling)
+ dev_dbg(dev,
+ "No interrupt pin definition, falling back to polling mode\n");
+
s->clk = devm_clk_get_optional(dev, NULL);
if (IS_ERR(s->clk))
return PTR_ERR(s->clk);
@@ -1532,17 +1598,23 @@ static int sc16is7xx_probe(struct device *dev,
}
sched_set_fifo(s->kworker_task);
- /* reset device, purging any pending irq / data */
- regmap_write(regmaps[0], SC16IS7XX_IOCONTROL_REG,
- SC16IS7XX_IOCONTROL_SRESET_BIT);
+ ret = sc16is7xx_reset(dev, regmaps[0]);
+ if (ret)
+ goto out_kthread;
+
+ /* Mark each port line and status as uninitialised. */
+ for (i = 0; i < devtype->nr_uart; ++i) {
+ s->p[i].port.line = SC16IS7XX_MAX_DEVS;
+ port_registered[i] = false;
+ }
for (i = 0; i < devtype->nr_uart; ++i) {
- s->p[i].port.line = find_first_zero_bit(sc16is7xx_lines,
- SC16IS7XX_MAX_DEVS);
- if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) {
- ret = -ERANGE;
+ ret = ida_alloc_max(&sc16is7xx_lines,
+ SC16IS7XX_MAX_DEVS - 1, GFP_KERNEL);
+ if (ret < 0)
goto out_ports;
- }
+
+ s->p[i].port.line = ret;
/* Initialize port data */
s->p[i].port.dev = dev;
@@ -1588,7 +1660,7 @@ static int sc16is7xx_probe(struct device *dev,
if (ret)
goto out_ports;
- set_bit(s->p[i].port.line, sc16is7xx_lines);
+ port_registered[i] = true;
/* Enable EFR */
sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_LCR_REG,
@@ -1621,6 +1693,12 @@ static int sc16is7xx_probe(struct device *dev,
goto out_ports;
#endif
+ if (s->polling) {
+ /* Initialize kernel thread for polling */
+ kthread_init_delayed_work(&s->poll_work, sc16is7xx_poll_proc);
+ return 0;
+ }
+
/*
* Setup interrupt. We first try to acquire the IRQ line as level IRQ.
* If that succeeds, we can allow sharing the interrupt as well.
@@ -1646,10 +1724,14 @@ static int sc16is7xx_probe(struct device *dev,
#endif
out_ports:
- for (i = 0; i < devtype->nr_uart; i++)
- if (test_and_clear_bit(s->p[i].port.line, sc16is7xx_lines))
+ for (i = 0; i < devtype->nr_uart; i++) {
+ if (s->p[i].port.line < SC16IS7XX_MAX_DEVS)
+ ida_free(&sc16is7xx_lines, s->p[i].port.line);
+ if (port_registered[i])
uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
+ }
+out_kthread:
kthread_stop(s->kworker_task);
out_clk:
@@ -1657,8 +1739,9 @@ out_clk:
return ret;
}
+EXPORT_SYMBOL_GPL(sc16is7xx_probe);
-static void sc16is7xx_remove(struct device *dev)
+void sc16is7xx_remove(struct device *dev)
{
struct sc16is7xx_port *s = dev_get_drvdata(dev);
int i;
@@ -1670,18 +1753,22 @@ static void sc16is7xx_remove(struct device *dev)
for (i = 0; i < s->devtype->nr_uart; i++) {
kthread_cancel_delayed_work_sync(&s->p[i].ms_work);
- if (test_and_clear_bit(s->p[i].port.line, sc16is7xx_lines))
- uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
+ ida_free(&sc16is7xx_lines, s->p[i].port.line);
+ uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port);
sc16is7xx_power(&s->p[i].port, 0);
}
+ if (s->polling)
+ kthread_cancel_delayed_work_sync(&s->poll_work);
+
kthread_flush_worker(&s->kworker);
kthread_stop(s->kworker_task);
clk_disable_unprepare(s->clk);
}
+EXPORT_SYMBOL_GPL(sc16is7xx_remove);
-static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
+const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
{ .compatible = "nxp,sc16is740", .data = &sc16is74x_devtype, },
{ .compatible = "nxp,sc16is741", .data = &sc16is74x_devtype, },
{ .compatible = "nxp,sc16is750", .data = &sc16is750_devtype, },
@@ -1690,13 +1777,14 @@ static const struct of_device_id __maybe_unused sc16is7xx_dt_ids[] = {
{ .compatible = "nxp,sc16is762", .data = &sc16is762_devtype, },
{ }
};
+EXPORT_SYMBOL_GPL(sc16is7xx_dt_ids);
MODULE_DEVICE_TABLE(of, sc16is7xx_dt_ids);
-static struct regmap_config regcfg = {
+const struct regmap_config sc16is7xx_regcfg = {
.reg_bits = 5,
.pad_bits = 3,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.volatile_reg = sc16is7xx_regmap_volatile,
.precious_reg = sc16is7xx_regmap_precious,
.writeable_noinc_reg = sc16is7xx_regmap_noinc,
@@ -1705,8 +1793,9 @@ static struct regmap_config regcfg = {
.max_raw_write = SC16IS7XX_FIFO_SIZE,
.max_register = SC16IS7XX_EFCR_REG,
};
+EXPORT_SYMBOL_GPL(sc16is7xx_regcfg);
-static const char *sc16is7xx_regmap_name(u8 port_id)
+const char *sc16is7xx_regmap_name(u8 port_id)
{
switch (port_id) {
case 0: return "port0";
@@ -1716,184 +1805,27 @@ static const char *sc16is7xx_regmap_name(u8 port_id)
return NULL;
}
}
+EXPORT_SYMBOL_GPL(sc16is7xx_regmap_name);
-static unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id)
+unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id)
{
/* CH1,CH0 are at bits 2:1. */
return port_id << 1;
}
-
-#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
-static int sc16is7xx_spi_probe(struct spi_device *spi)
-{
- const struct sc16is7xx_devtype *devtype;
- struct regmap *regmaps[SC16IS7XX_MAX_PORTS];
- unsigned int i;
- int ret;
-
- /* Setup SPI bus */
- spi->bits_per_word = 8;
- /* For all variants, only mode 0 is supported */
- if ((spi->mode & SPI_MODE_X_MASK) != SPI_MODE_0)
- return dev_err_probe(&spi->dev, -EINVAL, "Unsupported SPI mode\n");
-
- spi->mode = spi->mode ? : SPI_MODE_0;
- spi->max_speed_hz = spi->max_speed_hz ? : 4 * HZ_PER_MHZ;
- ret = spi_setup(spi);
- if (ret)
- return ret;
-
- devtype = spi_get_device_match_data(spi);
- if (!devtype)
- return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n");
-
- for (i = 0; i < devtype->nr_uart; i++) {
- regcfg.name = sc16is7xx_regmap_name(i);
- /*
- * If read_flag_mask is 0, the regmap code sets it to a default
- * of 0x80. Since we specify our own mask, we must add the READ
- * bit ourselves:
- */
- regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i) |
- SC16IS7XX_SPI_READ_BIT;
- regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i);
- regmaps[i] = devm_regmap_init_spi(spi, &regcfg);
- }
-
- return sc16is7xx_probe(&spi->dev, devtype, regmaps, spi->irq);
-}
-
-static void sc16is7xx_spi_remove(struct spi_device *spi)
-{
- sc16is7xx_remove(&spi->dev);
-}
-
-static const struct spi_device_id sc16is7xx_spi_id_table[] = {
- { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
- { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
- { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
- { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
- { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
- { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
- { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, },
- { }
-};
-
-MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table);
-
-static struct spi_driver sc16is7xx_spi_uart_driver = {
- .driver = {
- .name = SC16IS7XX_NAME,
- .of_match_table = sc16is7xx_dt_ids,
- },
- .probe = sc16is7xx_spi_probe,
- .remove = sc16is7xx_spi_remove,
- .id_table = sc16is7xx_spi_id_table,
-};
-#endif
-
-#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
-static int sc16is7xx_i2c_probe(struct i2c_client *i2c)
-{
- const struct sc16is7xx_devtype *devtype;
- struct regmap *regmaps[SC16IS7XX_MAX_PORTS];
- unsigned int i;
-
- devtype = i2c_get_match_data(i2c);
- if (!devtype)
- return dev_err_probe(&i2c->dev, -ENODEV, "Failed to match device\n");
-
- for (i = 0; i < devtype->nr_uart; i++) {
- regcfg.name = sc16is7xx_regmap_name(i);
- regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i);
- regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i);
- regmaps[i] = devm_regmap_init_i2c(i2c, &regcfg);
- }
-
- return sc16is7xx_probe(&i2c->dev, devtype, regmaps, i2c->irq);
-}
-
-static void sc16is7xx_i2c_remove(struct i2c_client *client)
-{
- sc16is7xx_remove(&client->dev);
-}
-
-static const struct i2c_device_id sc16is7xx_i2c_id_table[] = {
- { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
- { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
- { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
- { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
- { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
- { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
- { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table);
-
-static struct i2c_driver sc16is7xx_i2c_uart_driver = {
- .driver = {
- .name = SC16IS7XX_NAME,
- .of_match_table = sc16is7xx_dt_ids,
- },
- .probe = sc16is7xx_i2c_probe,
- .remove = sc16is7xx_i2c_remove,
- .id_table = sc16is7xx_i2c_id_table,
-};
-
-#endif
+EXPORT_SYMBOL_GPL(sc16is7xx_regmap_port_mask);
static int __init sc16is7xx_init(void)
{
- int ret;
-
- ret = uart_register_driver(&sc16is7xx_uart);
- if (ret) {
- pr_err("Registering UART driver failed\n");
- return ret;
- }
-
-#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
- ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver);
- if (ret < 0) {
- pr_err("failed to init sc16is7xx i2c --> %d\n", ret);
- goto err_i2c;
- }
-#endif
-
-#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
- ret = spi_register_driver(&sc16is7xx_spi_uart_driver);
- if (ret < 0) {
- pr_err("failed to init sc16is7xx spi --> %d\n", ret);
- goto err_spi;
- }
-#endif
- return ret;
-
-#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
-err_spi:
-#endif
-#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
- i2c_del_driver(&sc16is7xx_i2c_uart_driver);
-err_i2c:
-#endif
- uart_unregister_driver(&sc16is7xx_uart);
- return ret;
+ return uart_register_driver(&sc16is7xx_uart);
}
module_init(sc16is7xx_init);
static void __exit sc16is7xx_exit(void)
{
-#ifdef CONFIG_SERIAL_SC16IS7XX_I2C
- i2c_del_driver(&sc16is7xx_i2c_uart_driver);
-#endif
-
-#ifdef CONFIG_SERIAL_SC16IS7XX_SPI
- spi_unregister_driver(&sc16is7xx_spi_uart_driver);
-#endif
uart_unregister_driver(&sc16is7xx_uart);
}
module_exit(sc16is7xx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jon Ringle <jringle@gridpoint.com>");
-MODULE_DESCRIPTION("SC16IS7XX serial driver");
+MODULE_DESCRIPTION("SC16IS7xx tty serial core driver");
diff --git a/drivers/tty/serial/sc16is7xx.h b/drivers/tty/serial/sc16is7xx.h
new file mode 100644
index 000000000000..afb784eaee45
--- /dev/null
+++ b/drivers/tty/serial/sc16is7xx.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* SC16IS7xx SPI/I2C tty serial driver */
+
+#ifndef _SC16IS7XX_H_
+#define _SC16IS7XX_H_
+
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#define SC16IS7XX_NAME "sc16is7xx"
+#define SC16IS7XX_MAX_PORTS 2 /* Maximum number of UART ports per IC. */
+
+struct device;
+
+struct sc16is7xx_devtype {
+ char name[10];
+ int nr_gpio;
+ int nr_uart;
+};
+
+extern const struct regmap_config sc16is7xx_regcfg;
+
+extern const struct of_device_id sc16is7xx_dt_ids[];
+
+extern const struct sc16is7xx_devtype sc16is74x_devtype;
+extern const struct sc16is7xx_devtype sc16is750_devtype;
+extern const struct sc16is7xx_devtype sc16is752_devtype;
+extern const struct sc16is7xx_devtype sc16is760_devtype;
+extern const struct sc16is7xx_devtype sc16is762_devtype;
+
+const char *sc16is7xx_regmap_name(u8 port_id);
+
+unsigned int sc16is7xx_regmap_port_mask(unsigned int port_id);
+
+int sc16is7xx_probe(struct device *dev, const struct sc16is7xx_devtype *devtype,
+ struct regmap *regmaps[], int irq);
+
+void sc16is7xx_remove(struct device *dev);
+
+#endif /* _SC16IS7XX_H_ */
diff --git a/drivers/tty/serial/sc16is7xx_i2c.c b/drivers/tty/serial/sc16is7xx_i2c.c
new file mode 100644
index 000000000000..cd7de9e057b8
--- /dev/null
+++ b/drivers/tty/serial/sc16is7xx_i2c.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* SC16IS7xx I2C interface driver */
+
+#include <linux/dev_printk.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/string.h>
+
+#include "sc16is7xx.h"
+
+static int sc16is7xx_i2c_probe(struct i2c_client *i2c)
+{
+ const struct sc16is7xx_devtype *devtype;
+ struct regmap *regmaps[SC16IS7XX_MAX_PORTS];
+ struct regmap_config regcfg;
+ unsigned int i;
+
+ devtype = i2c_get_match_data(i2c);
+ if (!devtype)
+ return dev_err_probe(&i2c->dev, -ENODEV, "Failed to match device\n");
+
+ memcpy(&regcfg, &sc16is7xx_regcfg, sizeof(struct regmap_config));
+
+ for (i = 0; i < devtype->nr_uart; i++) {
+ regcfg.name = sc16is7xx_regmap_name(i);
+ regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i);
+ regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i);
+ regmaps[i] = devm_regmap_init_i2c(i2c, &regcfg);
+ }
+
+ return sc16is7xx_probe(&i2c->dev, devtype, regmaps, i2c->irq);
+}
+
+static void sc16is7xx_i2c_remove(struct i2c_client *client)
+{
+ sc16is7xx_remove(&client->dev);
+}
+
+static const struct i2c_device_id sc16is7xx_i2c_id_table[] = {
+ { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
+ { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
+ { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
+ { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table);
+
+static struct i2c_driver sc16is7xx_i2c_driver = {
+ .driver = {
+ .name = SC16IS7XX_NAME,
+ .of_match_table = sc16is7xx_dt_ids,
+ },
+ .probe = sc16is7xx_i2c_probe,
+ .remove = sc16is7xx_i2c_remove,
+ .id_table = sc16is7xx_i2c_id_table,
+};
+
+module_i2c_driver(sc16is7xx_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SC16IS7xx I2C interface driver");
+MODULE_IMPORT_NS("SERIAL_NXP_SC16IS7XX");
diff --git a/drivers/tty/serial/sc16is7xx_spi.c b/drivers/tty/serial/sc16is7xx_spi.c
new file mode 100644
index 000000000000..20d736b657b1
--- /dev/null
+++ b/drivers/tty/serial/sc16is7xx_spi.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* SC16IS7xx SPI interface driver */
+
+#include <linux/dev_printk.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/string.h>
+#include <linux/units.h>
+
+#include "sc16is7xx.h"
+
+/* SPI definitions */
+#define SC16IS7XX_SPI_READ_BIT BIT(7)
+
+static int sc16is7xx_spi_probe(struct spi_device *spi)
+{
+ const struct sc16is7xx_devtype *devtype;
+ struct regmap *regmaps[SC16IS7XX_MAX_PORTS];
+ struct regmap_config regcfg;
+ unsigned int i;
+ int ret;
+
+ /* Setup SPI bus */
+ spi->bits_per_word = 8;
+ /* For all variants, only mode 0 is supported */
+ if ((spi->mode & SPI_MODE_X_MASK) != SPI_MODE_0)
+ return dev_err_probe(&spi->dev, -EINVAL, "Unsupported SPI mode\n");
+
+ spi->mode = spi->mode ? : SPI_MODE_0;
+ spi->max_speed_hz = spi->max_speed_hz ? : 4 * HZ_PER_MHZ;
+ ret = spi_setup(spi);
+ if (ret)
+ return ret;
+
+ devtype = spi_get_device_match_data(spi);
+ if (!devtype)
+ return dev_err_probe(&spi->dev, -ENODEV, "Failed to match device\n");
+
+ memcpy(&regcfg, &sc16is7xx_regcfg, sizeof(struct regmap_config));
+
+ for (i = 0; i < devtype->nr_uart; i++) {
+ regcfg.name = sc16is7xx_regmap_name(i);
+ /*
+ * If read_flag_mask is 0, the regmap code sets it to a default
+ * of 0x80. Since we specify our own mask, we must add the READ
+ * bit ourselves:
+ */
+ regcfg.read_flag_mask = sc16is7xx_regmap_port_mask(i) |
+ SC16IS7XX_SPI_READ_BIT;
+ regcfg.write_flag_mask = sc16is7xx_regmap_port_mask(i);
+ regmaps[i] = devm_regmap_init_spi(spi, &regcfg);
+ }
+
+ return sc16is7xx_probe(&spi->dev, devtype, regmaps, spi->irq);
+}
+
+static void sc16is7xx_spi_remove(struct spi_device *spi)
+{
+ sc16is7xx_remove(&spi->dev);
+}
+
+static const struct spi_device_id sc16is7xx_spi_id_table[] = {
+ { "sc16is74x", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is740", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is741", (kernel_ulong_t)&sc16is74x_devtype, },
+ { "sc16is750", (kernel_ulong_t)&sc16is750_devtype, },
+ { "sc16is752", (kernel_ulong_t)&sc16is752_devtype, },
+ { "sc16is760", (kernel_ulong_t)&sc16is760_devtype, },
+ { "sc16is762", (kernel_ulong_t)&sc16is762_devtype, },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, sc16is7xx_spi_id_table);
+
+static struct spi_driver sc16is7xx_spi_driver = {
+ .driver = {
+ .name = SC16IS7XX_NAME,
+ .of_match_table = sc16is7xx_dt_ids,
+ },
+ .probe = sc16is7xx_spi_probe,
+ .remove = sc16is7xx_spi_remove,
+ .id_table = sc16is7xx_spi_id_table,
+};
+
+module_spi_driver(sc16is7xx_spi_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SC16IS7xx SPI interface driver");
+MODULE_IMPORT_NS("SERIAL_NXP_SC16IS7XX");
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index f24217a560d7..553e3c1321ca 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -439,7 +439,7 @@ static void sccnxp_handle_rx(struct uart_port *port)
static void sccnxp_handle_tx(struct uart_port *port)
{
u8 sr;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
struct sccnxp_port *s = dev_get_drvdata(port->dev);
if (unlikely(port->x_char)) {
@@ -449,7 +449,7 @@ static void sccnxp_handle_tx(struct uart_port *port)
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
/* Disable TX if FIFO is empty */
if (sccnxp_port_read(port, SCCNXP_SR_REG) & SR_TXEMT) {
sccnxp_disable_irq(port, IMR_TXRDY);
@@ -461,16 +461,20 @@ static void sccnxp_handle_tx(struct uart_port *port)
return;
}
- while (!uart_circ_empty(xmit)) {
+ while (1) {
+ unsigned char ch;
+
sr = sccnxp_port_read(port, SCCNXP_SR_REG);
if (!(sr & SR_TXRDY))
break;
- sccnxp_port_write(port, SCCNXP_THR_REG, xmit->buf[xmit->tail]);
- uart_xmit_advance(port, 1);
+ if (!uart_fifo_get(port, &ch))
+ break;
+
+ sccnxp_port_write(port, SCCNXP_THR_REG, ch);
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
@@ -1029,7 +1033,7 @@ static void sccnxp_remove(struct platform_device *pdev)
if (!s->poll)
devm_free_irq(&pdev->dev, s->irq, s);
else
- del_timer_sync(&s->timer);
+ timer_delete_sync(&s->timer);
for (i = 0; i < s->uart.nr; i++)
uart_remove_one_port(&s->uart, &s->port[i]);
@@ -1048,7 +1052,7 @@ static struct platform_driver sccnxp_uart_driver = {
.name = SCCNXP_NAME,
},
.probe = sccnxp_probe,
- .remove_new = sccnxp_remove,
+ .remove = sccnxp_remove,
.id_table = sccnxp_id_table,
};
module_platform_driver(sccnxp_uart_driver);
diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c
index 525f3a2f7bd4..8004fc00fb9c 100644
--- a/drivers/tty/serial/serial-tegra.c
+++ b/drivers/tty/serial/serial-tegra.c
@@ -484,18 +484,18 @@ static void tegra_uart_release_port(struct uart_port *u)
static void tegra_uart_fill_tx_fifo(struct tegra_uart_port *tup, int max_bytes)
{
- struct circ_buf *xmit = &tup->uport.state->xmit;
+ unsigned char ch;
int i;
for (i = 0; i < max_bytes; i++) {
- BUG_ON(uart_circ_empty(xmit));
if (tup->cdata->tx_fifo_full_status) {
unsigned long lsr = tegra_uart_read(tup, UART_LSR);
if ((lsr & TEGRA_UART_LSR_TXFIFO_FULL))
break;
}
- tegra_uart_write(tup, xmit->buf[xmit->tail], UART_TX);
- uart_xmit_advance(&tup->uport, 1);
+ if (WARN_ON_ONCE(!uart_fifo_get(&tup->uport, &ch)))
+ break;
+ tegra_uart_write(tup, ch, UART_TX);
}
}
@@ -514,7 +514,7 @@ static void tegra_uart_start_pio_tx(struct tegra_uart_port *tup,
static void tegra_uart_tx_dma_complete(void *args)
{
struct tegra_uart_port *tup = args;
- struct circ_buf *xmit = &tup->uport.state->xmit;
+ struct tty_port *tport = &tup->uport.state->port;
struct dma_tx_state state;
unsigned long flags;
unsigned int count;
@@ -525,7 +525,7 @@ static void tegra_uart_tx_dma_complete(void *args)
uart_port_lock_irqsave(&tup->uport, &flags);
uart_xmit_advance(&tup->uport, count);
tup->tx_in_progress = 0;
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&tup->uport);
tegra_uart_start_next_tx(tup);
uart_port_unlock_irqrestore(&tup->uport, flags);
@@ -534,11 +534,14 @@ static void tegra_uart_tx_dma_complete(void *args)
static int tegra_uart_start_tx_dma(struct tegra_uart_port *tup,
unsigned long count)
{
- struct circ_buf *xmit = &tup->uport.state->xmit;
+ struct tty_port *tport = &tup->uport.state->port;
dma_addr_t tx_phys_addr;
+ unsigned int tail;
tup->tx_bytes = count & ~(0xF);
- tx_phys_addr = tup->tx_dma_buf_phys + xmit->tail;
+ WARN_ON_ONCE(kfifo_out_linear(&tport->xmit_fifo, &tail,
+ UART_XMIT_SIZE) < count);
+ tx_phys_addr = tup->tx_dma_buf_phys + tail;
dma_sync_single_for_device(tup->uport.dev, tx_phys_addr,
tup->tx_bytes, DMA_TO_DEVICE);
@@ -562,18 +565,21 @@ static int tegra_uart_start_tx_dma(struct tegra_uart_port *tup,
static void tegra_uart_start_next_tx(struct tegra_uart_port *tup)
{
+ struct tty_port *tport = &tup->uport.state->port;
+ unsigned char *tail_ptr;
unsigned long tail;
- unsigned long count;
- struct circ_buf *xmit = &tup->uport.state->xmit;
+ unsigned int count;
if (!tup->current_baud)
return;
- tail = (unsigned long)&xmit->buf[xmit->tail];
- count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ count = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail_ptr,
+ UART_XMIT_SIZE);
if (!count)
return;
+ tail = (unsigned long)tail_ptr;
+
if (tup->use_tx_pio || count < TEGRA_UART_MIN_DMA)
tegra_uart_start_pio_tx(tup, count);
else if (BYTES_TO_ALIGN(tail) > 0)
@@ -586,9 +592,9 @@ static void tegra_uart_start_next_tx(struct tegra_uart_port *tup)
static void tegra_uart_start_tx(struct uart_port *u)
{
struct tegra_uart_port *tup = to_tegra_uport(u);
- struct circ_buf *xmit = &u->state->xmit;
+ struct tty_port *tport = &u->state->port;
- if (!uart_circ_empty(xmit) && !tup->tx_in_progress)
+ if (!kfifo_is_empty(&tport->xmit_fifo) && !tup->tx_in_progress)
tegra_uart_start_next_tx(tup);
}
@@ -628,11 +634,11 @@ static void tegra_uart_stop_tx(struct uart_port *u)
static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup)
{
- struct circ_buf *xmit = &tup->uport.state->xmit;
+ struct tty_port *tport = &tup->uport.state->port;
tegra_uart_fill_tx_fifo(tup, tup->tx_bytes);
tup->tx_in_progress = 0;
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&tup->uport);
tegra_uart_start_next_tx(tup);
}
@@ -1169,15 +1175,14 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup,
tup->rx_dma_buf_virt = dma_buf;
tup->rx_dma_buf_phys = dma_phys;
} else {
+ dma_buf = tup->uport.state->port.xmit_buf;
dma_phys = dma_map_single(tup->uport.dev,
- tup->uport.state->xmit.buf, UART_XMIT_SIZE,
- DMA_TO_DEVICE);
+ dma_buf, UART_XMIT_SIZE, DMA_TO_DEVICE);
if (dma_mapping_error(tup->uport.dev, dma_phys)) {
dev_err(tup->uport.dev, "dma_map_single tx failed\n");
dma_release_channel(dma_chan);
return -ENOMEM;
}
- dma_buf = tup->uport.state->xmit.buf;
dma_sconfig.dst_addr = tup->uport.mapbase;
dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma_sconfig.dst_maxburst = 16;
@@ -1643,7 +1648,7 @@ static const struct dev_pm_ops tegra_uart_pm_ops = {
static struct platform_driver tegra_uart_platform_driver = {
.probe = tegra_uart_probe,
- .remove_new = tegra_uart_remove,
+ .remove = tegra_uart_remove,
.driver = {
.name = "serial-tegra",
.of_match_table = tegra_uart_of_match,
diff --git a/drivers/tty/serial/serial_base.h b/drivers/tty/serial/serial_base.h
index b6c38d2edfd4..0d50db5b660b 100644
--- a/drivers/tty/serial/serial_base.h
+++ b/drivers/tty/serial/serial_base.h
@@ -49,3 +49,19 @@ void serial_ctrl_unregister_port(struct uart_driver *drv, struct uart_port *port
int serial_core_register_port(struct uart_driver *drv, struct uart_port *port);
void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port);
+
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+
+int serial_base_match_and_update_preferred_console(struct uart_driver *drv,
+ struct uart_port *port);
+
+#else
+
+static inline
+int serial_base_match_and_update_preferred_console(struct uart_driver *drv,
+ struct uart_port *port)
+{
+ return 0;
+}
+
+#endif
diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c
index 4df2a4b10445..5d1677f1b651 100644
--- a/drivers/tty/serial/serial_base_bus.c
+++ b/drivers/tty/serial/serial_base_bus.c
@@ -8,6 +8,7 @@
* The serial core bus manages the serial core controller instances.
*/
+#include <linux/cleanup.h>
#include <linux/container_of.h>
#include <linux/device.h>
#include <linux/idr.h>
@@ -28,7 +29,7 @@ static const struct device_type serial_port_type = {
.name = "port",
};
-static int serial_base_match(struct device *dev, struct device_driver *drv)
+static int serial_base_match(struct device *dev, const struct device_driver *drv)
{
if (dev->type == &serial_ctrl_type &&
str_has_prefix(drv->name, serial_ctrl_type.name))
@@ -204,6 +205,42 @@ void serial_base_port_device_remove(struct serial_port_device *port_dev)
put_device(&port_dev->dev);
}
+#ifdef CONFIG_SERIAL_CORE_CONSOLE
+
+/**
+ * serial_base_match_and_update_preferred_console - Match and update a preferred console
+ * @drv: Serial port device driver
+ * @port: Serial port instance
+ *
+ * Tries to match and update the preferred console for a serial port for
+ * the kernel command line option console=DEVNAME:0.0.
+ *
+ * Cannot be called early for ISA ports, depends on struct device.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int serial_base_match_and_update_preferred_console(struct uart_driver *drv,
+ struct uart_port *port)
+{
+ const char *port_match __free(kfree) = NULL;
+ int ret;
+
+ port_match = kasprintf(GFP_KERNEL, "%s:%d.%d", dev_name(port->dev),
+ port->ctrl_id, port->port_id);
+ if (!port_match)
+ return -ENOMEM;
+
+ ret = match_devname_and_update_preferred_console(port_match,
+ drv->dev_name,
+ port->line);
+ if (ret == -ENOENT)
+ return 0;
+
+ return ret;
+}
+
+#endif
+
static int serial_base_init(void)
{
int ret;
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index c476d884356d..88669972d9a0 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -243,25 +243,12 @@ static void uart_change_line_settings(struct tty_struct *tty, struct uart_state
uart_port_unlock_irq(uport);
}
-/*
- * Startup the port. This will be called once per open. All calls
- * will be serialised by the per-port mutex.
- */
-static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
- bool init_hw)
+static int uart_alloc_xmit_buf(struct tty_port *port)
{
- struct uart_port *uport = uart_port_check(state);
+ struct uart_state *state = container_of(port, struct uart_state, port);
+ struct uart_port *uport;
unsigned long flags;
unsigned long page;
- int retval = 0;
-
- if (uport->type == PORT_UNKNOWN)
- return 1;
-
- /*
- * Make sure the device is in D0 state.
- */
- uart_change_pm(state, UART_PM_STATE_ON);
/*
* Initialise and allocate the transmit and temporary
@@ -271,20 +258,68 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
if (!page)
return -ENOMEM;
- uart_port_lock(state, flags);
- if (!state->xmit.buf) {
- state->xmit.buf = (unsigned char *) page;
- uart_circ_clear(&state->xmit);
+ uport = uart_port_lock(state, flags);
+ if (!state->port.xmit_buf) {
+ state->port.xmit_buf = (unsigned char *)page;
+ kfifo_init(&state->port.xmit_fifo, state->port.xmit_buf,
+ PAGE_SIZE);
uart_port_unlock(uport, flags);
} else {
uart_port_unlock(uport, flags);
/*
* Do not free() the page under the port lock, see
- * uart_shutdown().
+ * uart_free_xmit_buf().
*/
free_page(page);
}
+ return 0;
+}
+
+static void uart_free_xmit_buf(struct tty_port *port)
+{
+ struct uart_state *state = container_of(port, struct uart_state, port);
+ struct uart_port *uport;
+ unsigned long flags;
+ char *xmit_buf;
+
+ /*
+ * Do not free() the transmit buffer page under the port lock since
+ * this can create various circular locking scenarios. For instance,
+ * console driver may need to allocate/free a debug object, which
+ * can end up in printk() recursion.
+ */
+ uport = uart_port_lock(state, flags);
+ xmit_buf = port->xmit_buf;
+ port->xmit_buf = NULL;
+ INIT_KFIFO(port->xmit_fifo);
+ uart_port_unlock(uport, flags);
+
+ free_page((unsigned long)xmit_buf);
+}
+
+/*
+ * Startup the port. This will be called once per open. All calls
+ * will be serialised by the per-port mutex.
+ */
+static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
+ bool init_hw)
+{
+ struct uart_port *uport = uart_port_check(state);
+ int retval;
+
+ if (uport->type == PORT_UNKNOWN)
+ return 1;
+
+ /*
+ * Make sure the device is in D0 state.
+ */
+ uart_change_pm(state, UART_PM_STATE_ON);
+
+ retval = uart_alloc_xmit_buf(&state->port);
+ if (retval)
+ return retval;
+
retval = uport->ops->startup(uport);
if (retval == 0) {
if (uart_console(uport) && uport->cons->cflag) {
@@ -356,8 +391,6 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
{
struct uart_port *uport = uart_port_check(state);
struct tty_port *port = &state->port;
- unsigned long flags;
- char *xmit_buf = NULL;
/*
* Set the TTY IO error marker
@@ -374,14 +407,16 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
/*
* Turn off DTR and RTS early.
*/
- if (uport && uart_console(uport) && tty) {
- uport->cons->cflag = tty->termios.c_cflag;
- uport->cons->ispeed = tty->termios.c_ispeed;
- uport->cons->ospeed = tty->termios.c_ospeed;
- }
+ if (uport) {
+ if (uart_console(uport) && tty) {
+ uport->cons->cflag = tty->termios.c_cflag;
+ uport->cons->ispeed = tty->termios.c_ispeed;
+ uport->cons->ospeed = tty->termios.c_ospeed;
+ }
- if (!tty || C_HUPCL(tty))
- uart_port_dtr_rts(uport, false);
+ if (!tty || C_HUPCL(tty))
+ uart_port_dtr_rts(uport, false);
+ }
uart_port_shutdown(port);
}
@@ -393,18 +428,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
*/
tty_port_set_suspended(port, false);
- /*
- * Do not free() the transmit buffer page under the port lock since
- * this can create various circular locking scenarios. For instance,
- * console driver may need to allocate/free a debug object, which
- * can endup in printk() recursion.
- */
- uart_port_lock(state, flags);
- xmit_buf = state->xmit.buf;
- state->xmit.buf = NULL;
- uart_port_unlock(uport, flags);
-
- free_page((unsigned long)xmit_buf);
+ uart_free_xmit_buf(port);
}
/**
@@ -565,22 +589,17 @@ static int uart_put_char(struct tty_struct *tty, u8 c)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port;
- struct circ_buf *circ;
unsigned long flags;
int ret = 0;
- circ = &state->xmit;
port = uart_port_lock(state, flags);
- if (!circ->buf) {
+ if (!state->port.xmit_buf) {
uart_port_unlock(port, flags);
return 0;
}
- if (port && uart_circ_chars_free(circ) != 0) {
- circ->buf[circ->head] = c;
- circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
- ret = 1;
- }
+ if (port)
+ ret = kfifo_put(&state->port.xmit_fifo, c);
uart_port_unlock(port, flags);
return ret;
}
@@ -594,9 +613,8 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port;
- struct circ_buf *circ;
unsigned long flags;
- int c, ret = 0;
+ int ret = 0;
/*
* This means you called this function _after_ the port was
@@ -606,24 +624,13 @@ static ssize_t uart_write(struct tty_struct *tty, const u8 *buf, size_t count)
return -EL3HLT;
port = uart_port_lock(state, flags);
- circ = &state->xmit;
- if (!circ->buf) {
+ if (!state->port.xmit_buf) {
uart_port_unlock(port, flags);
return 0;
}
- while (port) {
- c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
- if (count < c)
- c = count;
- if (c <= 0)
- break;
- memcpy(circ->buf + circ->head, buf, c);
- circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
- buf += c;
- count -= c;
- ret += c;
- }
+ if (port)
+ ret = kfifo_in(&state->port.xmit_fifo, buf, count);
__uart_start(state);
uart_port_unlock(port, flags);
@@ -638,7 +645,7 @@ static unsigned int uart_write_room(struct tty_struct *tty)
unsigned int ret;
port = uart_port_lock(state, flags);
- ret = uart_circ_chars_free(&state->xmit);
+ ret = kfifo_avail(&state->port.xmit_fifo);
uart_port_unlock(port, flags);
return ret;
}
@@ -651,7 +658,7 @@ static unsigned int uart_chars_in_buffer(struct tty_struct *tty)
unsigned int ret;
port = uart_port_lock(state, flags);
- ret = uart_circ_chars_pending(&state->xmit);
+ ret = kfifo_len(&state->port.xmit_fifo);
uart_port_unlock(port, flags);
return ret;
}
@@ -674,7 +681,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
port = uart_port_lock(state, flags);
if (!port)
return;
- uart_circ_clear(&state->xmit);
+ kfifo_reset(&state->port.xmit_fifo);
if (port->ops->flush_buffer)
port->ops->flush_buffer(port);
uart_port_unlock(port, flags);
@@ -783,7 +790,6 @@ static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport;
- int ret = -ENODEV;
/* Initialize structure in case we error out later to prevent any stack info leakage. */
*retinfo = (struct serial_struct){};
@@ -792,10 +798,10 @@ static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
* Ensure the state we copy is consistent and no hardware changes
* occur as we go
*/
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
uport = uart_port_check(state);
if (!uport)
- goto out;
+ return -ENODEV;
retinfo->type = uport->type;
retinfo->line = uport->line;
@@ -816,10 +822,7 @@ static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo)
retinfo->iomem_reg_shift = uport->regshift;
retinfo->iomem_base = (void *)(unsigned long)uport->mapbase;
- ret = 0;
-out:
- mutex_unlock(&port->mutex);
- return ret;
+ return 0;
}
static int uart_get_info_user(struct tty_struct *tty,
@@ -831,16 +834,71 @@ static int uart_get_info_user(struct tty_struct *tty,
return uart_get_info(port, ss) < 0 ? -EIO : 0;
}
+static int uart_change_port(struct uart_port *uport,
+ const struct serial_struct *new_info,
+ unsigned long new_port)
+{
+ unsigned long old_iobase, old_mapbase;
+ unsigned int old_type, old_iotype, old_hub6, old_shift;
+ int retval;
+
+ old_iobase = uport->iobase;
+ old_mapbase = uport->mapbase;
+ old_type = uport->type;
+ old_hub6 = uport->hub6;
+ old_iotype = uport->iotype;
+ old_shift = uport->regshift;
+
+ if (old_type != PORT_UNKNOWN && uport->ops->release_port)
+ uport->ops->release_port(uport);
+
+ uport->iobase = new_port;
+ uport->type = new_info->type;
+ uport->hub6 = new_info->hub6;
+ uport->iotype = new_info->io_type;
+ uport->regshift = new_info->iomem_reg_shift;
+ uport->mapbase = (unsigned long)new_info->iomem_base;
+
+ if (uport->type == PORT_UNKNOWN || !uport->ops->request_port)
+ return 0;
+
+ retval = uport->ops->request_port(uport);
+ if (retval == 0)
+ return 0; /* succeeded => done */
+
+ /*
+ * If we fail to request resources for the new port, try to restore the
+ * old settings.
+ */
+ uport->iobase = old_iobase;
+ uport->type = old_type;
+ uport->hub6 = old_hub6;
+ uport->iotype = old_iotype;
+ uport->regshift = old_shift;
+ uport->mapbase = old_mapbase;
+
+ if (old_type == PORT_UNKNOWN)
+ return retval;
+
+ retval = uport->ops->request_port(uport);
+ /* If we failed to restore the old settings, we fail like this. */
+ if (retval)
+ uport->type = PORT_UNKNOWN;
+
+ /* We failed anyway. */
+ return -EBUSY;
+}
+
static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
struct uart_state *state,
struct serial_struct *new_info)
{
struct uart_port *uport = uart_port_check(state);
unsigned long new_port;
- unsigned int change_irq, change_port, closing_wait;
- unsigned int old_custom_divisor, close_delay;
+ unsigned int old_custom_divisor, close_delay, closing_wait;
+ bool change_irq, change_port;
upf_t old_flags, new_flags;
- int retval = 0;
+ int retval;
if (!uport)
return -EIO;
@@ -876,8 +934,13 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
new_flags = (__force upf_t)new_info->flags;
old_custom_divisor = uport->custom_divisor;
+ if (!(uport->flags & UPF_FIXED_PORT)) {
+ unsigned int uartclk = new_info->baud_base * 16;
+ /* check needs to be done here before other settings made */
+ if (uartclk == 0)
+ return -EINVAL;
+ }
if (!capable(CAP_SYS_ADMIN)) {
- retval = -EPERM;
if (change_irq || change_port ||
(new_info->baud_base != uport->uartclk / 16) ||
(close_delay != port->close_delay) ||
@@ -885,7 +948,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
(new_info->xmit_fifo_size &&
new_info->xmit_fifo_size != uport->fifosize) ||
(((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
- goto exit;
+ return -EPERM;
uport->flags = ((uport->flags & ~UPF_USR_MASK) |
(new_flags & UPF_USR_MASK));
uport->custom_divisor = new_info->custom_divisor;
@@ -895,30 +958,24 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
if (change_irq || change_port) {
retval = security_locked_down(LOCKDOWN_TIOCSSERIAL);
if (retval)
- goto exit;
+ return retval;
}
- /*
- * Ask the low level driver to verify the settings.
- */
- if (uport->ops->verify_port)
+ /* Ask the low level driver to verify the settings. */
+ if (uport->ops->verify_port) {
retval = uport->ops->verify_port(uport, new_info);
+ if (retval)
+ return retval;
+ }
- if ((new_info->irq >= nr_irqs) || (new_info->irq < 0) ||
+ if ((new_info->irq >= irq_get_nr_irqs()) || (new_info->irq < 0) ||
(new_info->baud_base < 9600))
- retval = -EINVAL;
-
- if (retval)
- goto exit;
+ return -EINVAL;
if (change_port || change_irq) {
- retval = -EBUSY;
-
- /*
- * Make sure that we are the sole user of this port.
- */
+ /* Make sure that we are the sole user of this port. */
if (tty_port_users(port) > 1)
- goto exit;
+ return -EBUSY;
/*
* We need to shutdown the serial port at the old
@@ -928,69 +985,9 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
}
if (change_port) {
- unsigned long old_iobase, old_mapbase;
- unsigned int old_type, old_iotype, old_hub6, old_shift;
-
- old_iobase = uport->iobase;
- old_mapbase = uport->mapbase;
- old_type = uport->type;
- old_hub6 = uport->hub6;
- old_iotype = uport->iotype;
- old_shift = uport->regshift;
-
- /*
- * Free and release old regions
- */
- if (old_type != PORT_UNKNOWN && uport->ops->release_port)
- uport->ops->release_port(uport);
-
- uport->iobase = new_port;
- uport->type = new_info->type;
- uport->hub6 = new_info->hub6;
- uport->iotype = new_info->io_type;
- uport->regshift = new_info->iomem_reg_shift;
- uport->mapbase = (unsigned long)new_info->iomem_base;
-
- /*
- * Claim and map the new regions
- */
- if (uport->type != PORT_UNKNOWN && uport->ops->request_port) {
- retval = uport->ops->request_port(uport);
- } else {
- /* Always success - Jean II */
- retval = 0;
- }
-
- /*
- * If we fail to request resources for the
- * new port, try to restore the old settings.
- */
- if (retval) {
- uport->iobase = old_iobase;
- uport->type = old_type;
- uport->hub6 = old_hub6;
- uport->iotype = old_iotype;
- uport->regshift = old_shift;
- uport->mapbase = old_mapbase;
-
- if (old_type != PORT_UNKNOWN) {
- retval = uport->ops->request_port(uport);
- /*
- * If we failed to restore the old settings,
- * we fail like this.
- */
- if (retval)
- uport->type = PORT_UNKNOWN;
-
- /*
- * We failed anyway.
- */
- retval = -EBUSY;
- }
-
- /* Added to return the correct error -Ram Gupta */
- goto exit;
- }
+ retval = uart_change_port(uport, new_info, new_port);
+ if (retval)
+ return retval;
}
if (change_irq)
@@ -1006,9 +1003,9 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
uport->fifosize = new_info->xmit_fifo_size;
check_and_exit:
- retval = 0;
if (uport->type == PORT_UNKNOWN)
- goto exit;
+ return 0;
+
if (tty_port_initialized(port)) {
if (((old_flags ^ uport->flags) & UPF_SPD_MASK) ||
old_custom_divisor != uport->custom_divisor) {
@@ -1024,15 +1021,17 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port,
}
uart_change_line_settings(tty, state, NULL);
}
- } else {
- retval = uart_startup(tty, state, true);
- if (retval == 0)
- tty_port_set_initialized(port, true);
- if (retval > 0)
- retval = 0;
+
+ return 0;
}
- exit:
- return retval;
+
+ retval = uart_startup(tty, state, true);
+ if (retval < 0)
+ return retval;
+ if (retval == 0)
+ tty_port_set_initialized(port, true);
+
+ return 0;
}
static int uart_set_info_user(struct tty_struct *tty, struct serial_struct *ss)
@@ -1077,7 +1076,7 @@ static int uart_get_lsr_info(struct tty_struct *tty,
* interrupt happens).
*/
if (uport->x_char ||
- ((uart_circ_chars_pending(&state->xmit) > 0) &&
+ (!kfifo_is_empty(&state->port.xmit_fifo) &&
!uart_tx_stopped(uport)))
result &= ~TIOCSER_TEMT;
@@ -1089,21 +1088,19 @@ static int uart_tiocmget(struct tty_struct *tty)
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
struct uart_port *uport;
- int result = -EIO;
+ int result;
+
+ guard(mutex)(&port->mutex);
- mutex_lock(&port->mutex);
uport = uart_port_check(state);
- if (!uport)
- goto out;
+ if (!uport || tty_io_error(tty))
+ return -EIO;
+
+ uart_port_lock_irq(uport);
+ result = uport->mctrl;
+ result |= uport->ops->get_mctrl(uport);
+ uart_port_unlock_irq(uport);
- if (!tty_io_error(tty)) {
- uart_port_lock_irq(uport);
- result = uport->mctrl;
- result |= uport->ops->get_mctrl(uport);
- uart_port_unlock_irq(uport);
- }
-out:
- mutex_unlock(&port->mutex);
return result;
}
@@ -1113,20 +1110,16 @@ uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear)
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
struct uart_port *uport;
- int ret = -EIO;
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
+
uport = uart_port_check(state);
- if (!uport)
- goto out;
+ if (!uport || tty_io_error(tty))
+ return -EIO;
- if (!tty_io_error(tty)) {
- uart_update_mctrl(uport, set, clear);
- ret = 0;
- }
-out:
- mutex_unlock(&port->mutex);
- return ret;
+ uart_update_mctrl(uport, set, clear);
+
+ return 0;
}
static int uart_break_ctl(struct tty_struct *tty, int break_state)
@@ -1134,19 +1127,17 @@ static int uart_break_ctl(struct tty_struct *tty, int break_state)
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
struct uart_port *uport;
- int ret = -EIO;
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
+
uport = uart_port_check(state);
if (!uport)
- goto out;
+ return -EIO;
if (uport->type != PORT_UNKNOWN && uport->ops->break_ctl)
uport->ops->break_ctl(uport, break_state);
- ret = 0;
-out:
- mutex_unlock(&port->mutex);
- return ret;
+
+ return 0;
}
static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
@@ -1163,17 +1154,14 @@ static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
* changing, and hence any extra opens of the port while
* we're auto-configuring.
*/
- if (mutex_lock_interruptible(&port->mutex))
- return -ERESTARTSYS;
+ scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &port->mutex) {
+ uport = uart_port_check(state);
+ if (!uport)
+ return -EIO;
- uport = uart_port_check(state);
- if (!uport) {
- ret = -EIO;
- goto out;
- }
+ if (tty_port_users(port) != 1)
+ return -EBUSY;
- ret = -EBUSY;
- if (tty_port_users(port) == 1) {
uart_shutdown(tty, state);
/*
@@ -1194,14 +1182,15 @@ static int uart_do_autoconfig(struct tty_struct *tty, struct uart_state *state)
uport->ops->config_port(uport, flags);
ret = uart_startup(tty, state, true);
- if (ret == 0)
- tty_port_set_initialized(port, true);
+ if (ret < 0)
+ return ret;
if (ret > 0)
- ret = 0;
+ return 0;
+
+ tty_port_set_initialized(port, true);
}
-out:
- mutex_unlock(&port->mutex);
- return ret;
+
+ return 0;
}
static void uart_enable_ms(struct uart_port *uport)
@@ -1696,10 +1685,11 @@ static void uart_set_termios(struct tty_struct *tty,
unsigned int iflag_mask = IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK;
bool sw_changed = false;
- mutex_lock(&state->port.mutex);
+ guard(mutex)(&state->port.mutex);
+
uport = uart_port_check(state);
if (!uport)
- goto out;
+ return;
/*
* Drivers doing software flow control also need to know
@@ -1722,9 +1712,8 @@ static void uart_set_termios(struct tty_struct *tty,
tty->termios.c_ospeed == old_termios->c_ospeed &&
tty->termios.c_ispeed == old_termios->c_ispeed &&
((tty->termios.c_iflag ^ old_termios->c_iflag) & iflag_mask) == 0 &&
- !sw_changed) {
- goto out;
- }
+ !sw_changed)
+ return;
uart_change_line_settings(tty, state, old_termios);
/* reload cflag from termios; port driver may have overridden flags */
@@ -1741,8 +1730,6 @@ static void uart_set_termios(struct tty_struct *tty,
mask |= TIOCM_RTS;
uart_set_mctrl(uport, mask);
}
-out:
- mutex_unlock(&state->port.mutex);
}
/*
@@ -1775,7 +1762,6 @@ static void uart_tty_port_shutdown(struct tty_port *port)
{
struct uart_state *state = container_of(port, struct uart_state, port);
struct uart_port *uport = uart_port_check(state);
- char *buf;
/*
* At this point, we stop accepting input. To do this, we
@@ -1798,16 +1784,7 @@ static void uart_tty_port_shutdown(struct tty_port *port)
*/
tty_port_set_suspended(port, false);
- /*
- * Free the transmit buffer.
- */
- uart_port_lock_irq(uport);
- uart_circ_clear(&state->xmit);
- buf = state->xmit.buf;
- state->xmit.buf = NULL;
- uart_port_unlock_irq(uport);
-
- free_page((unsigned long)buf);
+ uart_free_xmit_buf(port);
uart_change_pm(state, UART_PM_STATE_OFF);
}
@@ -2036,9 +2013,8 @@ static const char *uart_type(struct uart_port *port)
#ifdef CONFIG_PROC_FS
-static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
+static void uart_line_info(struct seq_file *m, struct uart_state *state)
{
- struct uart_state *state = drv->state + i;
struct tty_port *port = &state->port;
enum uart_pm_state pm_state;
struct uart_port *uport;
@@ -2046,10 +2022,11 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
unsigned int status;
int mmio;
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
+
uport = uart_port_check(state);
if (!uport)
- goto out;
+ return;
mmio = uport->iotype >= UPIO_MEM;
seq_printf(m, "%d: uart:%s %s%08llX irq:%d",
@@ -2061,7 +2038,7 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
if (uport->type == PORT_UNKNOWN) {
seq_putc(m, '\n');
- goto out;
+ return;
}
if (capable(CAP_SYS_ADMIN)) {
@@ -2112,8 +2089,6 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
seq_putc(m, '\n');
#undef STATBIT
#undef INFOBIT
-out:
- mutex_unlock(&port->mutex);
}
static int uart_proc_show(struct seq_file *m, void *v)
@@ -2124,7 +2099,7 @@ static int uart_proc_show(struct seq_file *m, void *v)
seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", "");
for (i = 0; i < drv->nr; i++)
- uart_line_info(m, drv, i);
+ uart_line_info(m, drv->state + i);
return 0;
}
#endif
@@ -2373,9 +2348,9 @@ struct uart_match {
struct uart_driver *driver;
};
-static int serial_match_port(struct device *dev, void *data)
+static int serial_match_port(struct device *dev, const void *data)
{
- struct uart_match *match = data;
+ const struct uart_match *match = data;
struct tty_driver *tty_drv = match->driver->tty_driver;
dev_t devt = MKDEV(tty_drv->major, tty_drv->minor_start) +
match->port->line;
@@ -2390,13 +2365,12 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
struct device *tty_dev;
struct uart_match match = {uport, drv};
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
tty_dev = device_find_child(&uport->port_dev->dev, &match, serial_match_port);
if (tty_dev && device_may_wakeup(tty_dev)) {
enable_irq_wake(uport->irq);
put_device(tty_dev);
- mutex_unlock(&port->mutex);
return 0;
}
put_device(tty_dev);
@@ -2413,7 +2387,8 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
uport->ops->stop_rx(uport);
uart_port_unlock_irq(uport);
}
- goto unlock;
+ device_set_awake_path(uport->dev);
+ return 0;
}
uport->suspended = 1;
@@ -2450,14 +2425,12 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
}
/*
- * Disable the console device before suspending.
+ * Suspend the console device before suspending the port.
*/
if (uart_console(uport))
- console_stop(uport->cons);
+ console_suspend(uport->cons);
uart_change_pm(state, UART_PM_STATE_OFF);
-unlock:
- mutex_unlock(&port->mutex);
return 0;
}
@@ -2471,14 +2444,13 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
struct uart_match match = {uport, drv};
struct ktermios termios;
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
tty_dev = device_find_child(&uport->port_dev->dev, &match, serial_match_port);
if (!uport->suspended && device_may_wakeup(tty_dev)) {
if (irqd_is_wakeup_set(irq_get_irq_data((uport->irq))))
disable_irq_wake(uport->irq);
put_device(tty_dev);
- mutex_unlock(&port->mutex);
return 0;
}
put_device(tty_dev);
@@ -2511,7 +2483,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
uart_port_unlock_irq(uport);
}
if (console_suspend_enabled)
- console_start(uport->cons);
+ console_resume(uport->cons);
}
if (tty_port_suspended(port)) {
@@ -2551,8 +2523,6 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
tty_port_set_suspended(port, false);
}
- mutex_unlock(&port->mutex);
-
return 0;
}
EXPORT_SYMBOL(uart_resume_port);
@@ -2692,14 +2662,13 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options)
int ret = 0;
tport = &state->port;
- mutex_lock(&tport->mutex);
+
+ guard(mutex)(&tport->mutex);
port = uart_port_check(state);
if (!port || port->type == PORT_UNKNOWN ||
- !(port->ops->poll_get_char && port->ops->poll_put_char)) {
- ret = -1;
- goto out;
- }
+ !(port->ops->poll_get_char && port->ops->poll_put_char))
+ return -1;
pm_state = state->pm_state;
uart_change_pm(state, UART_PM_STATE_ON);
@@ -2719,10 +2688,10 @@ static int uart_poll_init(struct tty_driver *driver, int line, char *options)
ret = uart_set_options(port, NULL, baud, parity, bits, flow);
console_list_unlock();
}
-out:
+
if (ret)
uart_change_pm(state, pm_state);
- mutex_unlock(&tport->mutex);
+
return ret;
}
@@ -3075,26 +3044,25 @@ static ssize_t console_store(struct device *dev,
if (ret)
return ret;
- mutex_lock(&port->mutex);
+ guard(mutex)(&port->mutex);
uport = uart_port_check(state);
- if (uport) {
- oldconsole = uart_console_registered(uport);
- if (oldconsole && !newconsole) {
- ret = unregister_console(uport->cons);
- } else if (!oldconsole && newconsole) {
- if (uart_console(uport)) {
- uport->console_reinit = 1;
- register_console(uport->cons);
- } else {
- ret = -ENOENT;
- }
- }
- } else {
- ret = -ENXIO;
+ if (!uport)
+ return -ENXIO;
+
+ oldconsole = uart_console_registered(uport);
+ if (oldconsole && !newconsole) {
+ ret = unregister_console(uport->cons);
+ if (ret < 0)
+ return ret;
+ } else if (!oldconsole && newconsole) {
+ if (!uart_console(uport))
+ return -ENOENT;
+
+ uport->console_reinit = 1;
+ register_console(uport->cons);
}
- mutex_unlock(&port->mutex);
- return ret < 0 ? ret : count;
+ return count;
}
static DEVICE_ATTR_RO(uartclk);
@@ -3150,7 +3118,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
{
struct uart_state *state;
struct tty_port *port;
- int ret = 0;
struct device *tty_dev;
int num_groups;
@@ -3160,11 +3127,9 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
state = drv->state + uport->line;
port = &state->port;
- mutex_lock(&port->mutex);
- if (state->uart_port) {
- ret = -EINVAL;
- goto out;
- }
+ guard(mutex)(&port->mutex);
+ if (state->uart_port)
+ return -EINVAL;
/* Link the port to the driver state table and vice versa */
atomic_set(&state->refcount, 1);
@@ -3172,16 +3137,6 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
state->uart_port = uport;
uport->state = state;
- state->pm_state = UART_PM_STATE_UNDEFINED;
- uport->cons = drv->cons;
- uport->minor = drv->tty_driver->minor_start + uport->line;
- uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name,
- drv->tty_driver->name_base + uport->line);
- if (!uport->name) {
- ret = -ENOMEM;
- goto out;
- }
-
/*
* If this port is in use as a console then the spinlock is already
* initialised.
@@ -3189,10 +3144,17 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
if (!uart_console_registered(uport))
uart_port_spin_lock_init(uport);
+ state->pm_state = UART_PM_STATE_UNDEFINED;
+ uart_port_set_cons(uport, drv->cons);
+ uport->minor = drv->tty_driver->minor_start + uport->line;
+ uport->name = kasprintf(GFP_KERNEL, "%s%d", drv->dev_name,
+ drv->tty_driver->name_base + uport->line);
+ if (!uport->name)
+ return -ENOMEM;
+
if (uport->cons && uport->dev)
of_console_check(uport->dev->of_node, uport->cons->name, uport->line);
- tty_port_link_device(port, drv->tty_driver, uport->line);
uart_configure_port(drv, state, uport);
port->console = uart_console(uport);
@@ -3203,14 +3165,16 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
uport->tty_groups = kcalloc(num_groups, sizeof(*uport->tty_groups),
GFP_KERNEL);
- if (!uport->tty_groups) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!uport->tty_groups)
+ return -ENOMEM;
+
uport->tty_groups[0] = &tty_dev_attr_group;
if (uport->attr_group)
uport->tty_groups[1] = uport->attr_group;
+ /* Ensure serdev drivers can call serdev_device_open() right away */
+ uport->flags &= ~UPF_DEAD;
+
/*
* Register the port whether it's detected or not. This allows
* setserial to be used to alter this port's parameters.
@@ -3221,14 +3185,12 @@ static int serial_core_add_one_port(struct uart_driver *drv, struct uart_port *u
if (!IS_ERR(tty_dev)) {
device_set_wakeup_capable(tty_dev, 1);
} else {
+ uport->flags |= UPF_DEAD;
dev_err(uport->dev, "Cannot register tty device on line %d\n",
uport->line);
}
- out:
- mutex_unlock(&port->mutex);
-
- return ret;
+ return 0;
}
/**
@@ -3394,7 +3356,7 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port)
struct serial_ctrl_device *ctrl_dev, *new_ctrl_dev = NULL;
int ret;
- mutex_lock(&port_mutex);
+ guard(mutex)(&port_mutex);
/*
* Prevent serial_port_runtime_resume() from trying to use the port
@@ -3406,10 +3368,8 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port)
ctrl_dev = serial_core_ctrl_find(drv, port->dev, port->ctrl_id);
if (!ctrl_dev) {
new_ctrl_dev = serial_core_ctrl_device_add(port);
- if (IS_ERR(new_ctrl_dev)) {
- ret = PTR_ERR(new_ctrl_dev);
- goto err_unlock;
- }
+ if (IS_ERR(new_ctrl_dev))
+ return PTR_ERR(new_ctrl_dev);
ctrl_dev = new_ctrl_dev;
}
@@ -3422,13 +3382,13 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port)
if (ret)
goto err_unregister_ctrl_dev;
- ret = serial_core_add_one_port(drv, port);
+ ret = serial_base_match_and_update_preferred_console(drv, port);
if (ret)
goto err_unregister_port_dev;
- port->flags &= ~UPF_DEAD;
-
- mutex_unlock(&port_mutex);
+ ret = serial_core_add_one_port(drv, port);
+ if (ret)
+ goto err_unregister_port_dev;
return 0;
@@ -3438,9 +3398,6 @@ err_unregister_port_dev:
err_unregister_ctrl_dev:
serial_base_ctrl_device_remove(new_ctrl_dev);
-err_unlock:
- mutex_unlock(&port_mutex);
-
return ret;
}
diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c
index e51ca593ab86..7b02c5ca4afd 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.c
+++ b/drivers/tty/serial/serial_mctrl_gpio.c
@@ -217,7 +217,7 @@ static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context)
*
* This will get the {cts,rts,...}-gpios from device tree if they are present
* and request them, set direction etc, and return an allocated structure.
- * `devm_*` functions are used, so there's no need to call mctrl_gpio_free().
+ * `devm_*` functions are used, so there's no need to explicitly free.
* As this sets up the irq handling, make sure to not handle changes to the
* gpio input lines in your driver, too.
*/
@@ -268,32 +268,6 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx)
EXPORT_SYMBOL_GPL(mctrl_gpio_init);
/**
- * mctrl_gpio_free - explicitly free uart gpios
- * @dev: uart port's device
- * @gpios: gpios structure to be freed
- *
- * This will free the requested gpios in mctrl_gpio_init(). As `devm_*`
- * functions are used, there's generally no need to call this function.
- */
-void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
-{
- enum mctrl_gpio_idx i;
-
- if (gpios == NULL)
- return;
-
- for (i = 0; i < UART_GPIO_MAX; i++) {
- if (gpios->irq[i])
- devm_free_irq(gpios->port->dev, gpios->irq[i], gpios);
-
- if (gpios->gpio[i])
- devm_gpiod_put(dev, gpios->gpio[i]);
- }
- devm_kfree(dev, gpios);
-}
-EXPORT_SYMBOL_GPL(mctrl_gpio_free);
-
-/**
* mctrl_gpio_enable_ms - enable irqs and handling of changes to the ms lines
* @gpios: gpios to enable
*/
@@ -322,11 +296,7 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
}
EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms);
-/**
- * mctrl_gpio_disable_ms - disable irqs and handling of changes to the ms lines
- * @gpios: gpios to disable
- */
-void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
+static void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios, bool sync)
{
enum mctrl_gpio_idx i;
@@ -342,10 +312,34 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
if (!gpios->irq[i])
continue;
- disable_irq(gpios->irq[i]);
+ if (sync)
+ disable_irq(gpios->irq[i]);
+ else
+ disable_irq_nosync(gpios->irq[i]);
}
}
-EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms);
+
+/**
+ * mctrl_gpio_disable_ms_sync - disable irqs and handling of changes to the ms
+ * lines, and wait for any pending IRQ to be processed
+ * @gpios: gpios to disable
+ */
+void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios)
+{
+ mctrl_gpio_disable_ms(gpios, true);
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_sync);
+
+/**
+ * mctrl_gpio_disable_ms_no_sync - disable irqs and handling of changes to the
+ * ms lines, and return immediately
+ * @gpios: gpios to disable
+ */
+void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios)
+{
+ mctrl_gpio_disable_ms(gpios, false);
+}
+EXPORT_SYMBOL_GPL(mctrl_gpio_disable_ms_no_sync);
void mctrl_gpio_enable_irq_wake(struct mctrl_gpios *gpios)
{
@@ -385,4 +379,5 @@ void mctrl_gpio_disable_irq_wake(struct mctrl_gpios *gpios)
}
EXPORT_SYMBOL_GPL(mctrl_gpio_disable_irq_wake);
+MODULE_DESCRIPTION("Helpers for controlling modem lines via GPIO");
MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h
index fc76910fb105..961e4ba0c6f8 100644
--- a/drivers/tty/serial/serial_mctrl_gpio.h
+++ b/drivers/tty/serial/serial_mctrl_gpio.h
@@ -59,7 +59,7 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios,
/*
* Request and set direction of modem control line GPIOs and set up irq
* handling.
- * devm_* functions are used, so there's no need to call mctrl_gpio_free().
+ * devm_* functions are used, so there's no need to explicitly free.
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
* allocation error.
*/
@@ -67,7 +67,7 @@ struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx);
/*
* Request and set direction of modem control line GPIOs.
- * devm_* functions are used, so there's no need to call mctrl_gpio_free().
+ * devm_* functions are used, so there's no need to explicitly free.
* Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on
* allocation error.
*/
@@ -75,21 +75,21 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev,
unsigned int idx);
/*
- * Free the mctrl_gpios structure.
- * Normally, this function will not be called, as the GPIOs will
- * be disposed of by the resource management code.
+ * Enable gpio interrupts to report status line changes.
*/
-void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios);
+void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
/*
- * Enable gpio interrupts to report status line changes.
+ * Disable gpio interrupts to report status line changes, and block until
+ * any corresponding IRQ is processed
*/
-void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios);
+void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios);
/*
- * Disable gpio interrupts to report status line changes.
+ * Disable gpio interrupts to report status line changes, and return
+ * immediately
*/
-void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios);
+void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios);
/*
* Enable gpio wakeup interrupts to enable wake up source.
@@ -139,16 +139,15 @@ struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx)
return NULL;
}
-static inline
-void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios)
+static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
{
}
-static inline void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios)
+static inline void mctrl_gpio_disable_ms_sync(struct mctrl_gpios *gpios)
{
}
-static inline void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios)
+static inline void mctrl_gpio_disable_ms_no_sync(struct mctrl_gpios *gpios)
{
}
diff --git a/drivers/tty/serial/serial_port.c b/drivers/tty/serial/serial_port.c
index 7e3a1c7b097c..2fc48cd63f6c 100644
--- a/drivers/tty/serial/serial_port.c
+++ b/drivers/tty/serial/serial_port.c
@@ -11,6 +11,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/pnp.h>
#include <linux/property.h>
#include <linux/serial_core.h>
#include <linux/spinlock.h>
@@ -23,7 +24,7 @@
static int __serial_port_busy(struct uart_port *port)
{
return !uart_tx_stopped(port) &&
- uart_circ_chars_pending(&port->state->xmit);
+ !kfifo_is_empty(&port->state->port.xmit_fifo);
}
static int serial_port_runtime_resume(struct device *dev)
@@ -63,6 +64,13 @@ static int serial_port_runtime_suspend(struct device *dev)
if (port->flags & UPF_DEAD)
return 0;
+ /*
+ * Nothing to do on pm_runtime_force_suspend(), see
+ * DEFINE_RUNTIME_DEV_PM_OPS.
+ */
+ if (!pm_runtime_enabled(dev))
+ return 0;
+
uart_port_lock_irqsave(port, &flags);
if (!port_dev->tx_enabled) {
uart_port_unlock_irqrestore(port, flags);
@@ -165,6 +173,7 @@ EXPORT_SYMBOL(uart_remove_one_port);
* The caller is responsible to initialize the following fields of the @port
* ->dev (must be valid)
* ->flags
+ * ->iobase
* ->mapbase
* ->mapsize
* ->regshift (if @use_defaults is false)
@@ -206,7 +215,7 @@ static int __uart_read_properties(struct uart_port *port, bool use_defaults)
/* Read the registers I/O access type (default: MMIO 8-bit) */
ret = device_property_read_u32(dev, "reg-io-width", &value);
if (ret) {
- port->iotype = UPIO_MEM;
+ port->iotype = port->iobase ? UPIO_PORT : UPIO_MEM;
} else {
switch (value) {
case 1:
@@ -219,15 +228,16 @@ static int __uart_read_properties(struct uart_port *port, bool use_defaults)
port->iotype = device_is_big_endian(dev) ? UPIO_MEM32BE : UPIO_MEM32;
break;
default:
- if (!use_defaults) {
- dev_err(dev, "Unsupported reg-io-width (%u)\n", value);
- return -EINVAL;
- }
port->iotype = UPIO_UNKNOWN;
break;
}
}
+ if (!use_defaults && port->iotype == UPIO_UNKNOWN) {
+ dev_err(dev, "Unsupported reg-io-width (%u)\n", value);
+ return -EINVAL;
+ }
+
/* Read the address mapping base offset (default: no offset) */
ret = device_property_read_u32(dev, "reg-offset", &value);
if (ret)
@@ -255,7 +265,11 @@ static int __uart_read_properties(struct uart_port *port, bool use_defaults)
if (dev_is_platform(dev))
ret = platform_get_irq(to_platform_device(dev), 0);
- else
+ else if (dev_is_pnp(dev)) {
+ ret = pnp_irq(to_pnp_dev(dev), 0);
+ if (ret < 0)
+ ret = -ENXIO;
+ } else
ret = fwnode_irq_get(dev_fwnode(dev), 0);
if (ret == -EPROBE_DEFER)
return ret;
diff --git a/drivers/tty/serial/serial_txx9.c b/drivers/tty/serial/serial_txx9.c
index abba39722958..436a559234df 100644
--- a/drivers/tty/serial/serial_txx9.c
+++ b/drivers/tty/serial/serial_txx9.c
@@ -1097,7 +1097,7 @@ static int serial_txx9_resume(struct platform_device *dev)
static struct platform_driver serial_txx9_plat_driver = {
.probe = serial_txx9_probe,
- .remove_new = serial_txx9_remove,
+ .remove = serial_txx9_remove,
#ifdef CONFIG_PM
.suspend = serial_txx9_suspend,
.resume = serial_txx9_resume,
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index e512eaa57ed5..7e7813ccda41 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -104,6 +104,20 @@ struct plat_sci_reg {
u8 offset, size;
};
+struct sci_suspend_regs {
+ u16 scdl;
+ u16 sccks;
+ u16 scsmr;
+ u16 scscr;
+ u16 scfcr;
+ u16 scsptr;
+ u16 hssrr;
+ u16 scpcr;
+ u16 scpdr;
+ u8 scbrr;
+ u8 semr;
+};
+
struct sci_port_params {
const struct plat_sci_reg regs[SCIx_NR_REGS];
unsigned int fifosize;
@@ -134,6 +148,8 @@ struct sci_port {
struct dma_chan *chan_tx;
struct dma_chan *chan_rx;
+ struct reset_control *rstc;
+
#ifdef CONFIG_SERIAL_SH_SCI_DMA
struct dma_chan *chan_tx_saved;
struct dma_chan *chan_rx_saved;
@@ -153,10 +169,12 @@ struct sci_port {
int rx_trigger;
struct timer_list rx_fifo_timer;
int rx_fifo_timeout;
+ struct sci_suspend_regs suspend_regs;
u16 hscif_tot;
bool has_rtscts;
bool autorts;
+ bool tx_occurred;
};
#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
@@ -164,6 +182,8 @@ struct sci_port {
static struct sci_port sci_ports[SCI_NPORTS];
static unsigned long sci_ports_in_use;
static struct uart_driver sci_uart_driver;
+static bool sci_uart_earlycon;
+static bool sci_uart_earlycon_dev_probing;
static inline struct sci_port *
to_sci_port(struct uart_port *uart)
@@ -318,6 +338,37 @@ static const struct sci_port_params sci_port_params[SCIx_NR_REGTYPES] = {
},
/*
+ * The "SCIF" that is in RZ/V2H(P) SoC is similar to one found on RZ/G2L SoC
+ * with below differences,
+ * - Break out of interrupts are different: ERI, BRI, RXI, TXI, TEI, DRI,
+ * TEI-DRI, RXI-EDGE and TXI-EDGE.
+ * - SCSMR register does not have CM bit (BIT(7)) ie it does not support synchronous mode.
+ * - SCFCR register does not have SCFCR_MCE bit.
+ * - SCSPTR register has only bits SCSPTR_SPB2DT and SCSPTR_SPB2IO.
+ */
+ [SCIx_RZV2H_SCIF_REGTYPE] = {
+ .regs = {
+ [SCSMR] = { 0x00, 16 },
+ [SCBRR] = { 0x02, 8 },
+ [SCSCR] = { 0x04, 16 },
+ [SCxTDR] = { 0x06, 8 },
+ [SCxSR] = { 0x08, 16 },
+ [SCxRDR] = { 0x0a, 8 },
+ [SCFCR] = { 0x0c, 16 },
+ [SCFDR] = { 0x0e, 16 },
+ [SCSPTR] = { 0x10, 16 },
+ [SCLSR] = { 0x12, 16 },
+ [SEMR] = { 0x14, 8 },
+ },
+ .fifosize = 16,
+ .overrun_reg = SCLSR,
+ .overrun_mask = SCLSR_ORER,
+ .sampling_rate_mask = SCI_SR(32),
+ .error_mask = SCIF_DEFAULT_ERROR_MASK,
+ .error_clear = SCIF_ERROR_CLEAR,
+ },
+
+ /*
* Common SH-3 SCIF definitions.
*/
[SCIx_SH3_SCIF_REGTYPE] = {
@@ -585,7 +636,7 @@ static void sci_start_tx(struct uart_port *port)
sci_serial_out(port, SCSCR, new);
}
- if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) &&
+ if (s->chan_tx && !kfifo_is_empty(&port->state->port.xmit_fifo) &&
dma_submit_error(s->cookie_tx)) {
if (s->cfg->regtype == SCIx_RZ_SCIFA_REGTYPE)
/* Switch irq from SCIF to DMA */
@@ -757,7 +808,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag)
}
sci_serial_out(port, SCPDR, data);
sci_serial_out(port, SCPCR, ctrl);
- } else if (sci_getreg(port, SCSPTR)->size) {
+ } else if (sci_getreg(port, SCSPTR)->size && s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE) {
u16 status = sci_serial_in(port, SCSPTR);
/* RTS# is always output; and active low, unless autorts */
@@ -817,8 +868,9 @@ static int sci_rxfill(struct uart_port *port)
static void sci_transmit_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
unsigned int stopped = uart_tx_stopped(port);
+ struct sci_port *s = to_sci_port(port);
unsigned short status;
unsigned short ctrl;
int count;
@@ -826,7 +878,7 @@ static void sci_transmit_chars(struct uart_port *port)
status = sci_serial_in(port, SCxSR);
if (!(status & SCxSR_TDxE(port))) {
ctrl = sci_serial_in(port, SCSCR);
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
ctrl &= ~SCSCR_TIE;
else
ctrl |= SCSCR_TIE;
@@ -842,28 +894,28 @@ static void sci_transmit_chars(struct uart_port *port)
if (port->x_char) {
c = port->x_char;
port->x_char = 0;
- } else if (!uart_circ_empty(xmit) && !stopped) {
- c = xmit->buf[xmit->tail];
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- } else if (port->type == PORT_SCI && uart_circ_empty(xmit)) {
- ctrl = sci_serial_in(port, SCSCR);
- ctrl &= ~SCSCR_TE;
- sci_serial_out(port, SCSCR, ctrl);
- return;
- } else {
+ } else if (stopped || !kfifo_get(&tport->xmit_fifo, &c)) {
+ if (port->type == PORT_SCI &&
+ kfifo_is_empty(&tport->xmit_fifo)) {
+ ctrl = sci_serial_in(port, SCSCR);
+ ctrl &= ~SCSCR_TE;
+ sci_serial_out(port, SCSCR, ctrl);
+ return;
+ }
break;
}
sci_serial_out(port, SCxTDR, c);
+ s->tx_occurred = true;
port->icount.tx++;
} while (--count > 0);
sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port));
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit)) {
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
if (port->type == PORT_SCI) {
ctrl = sci_serial_in(port, SCSCR);
ctrl &= ~SCSCR_TIE;
@@ -1199,7 +1251,7 @@ static void sci_dma_tx_complete(void *arg)
{
struct sci_port *s = arg;
struct uart_port *port = &s->port;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
unsigned long flags;
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
@@ -1208,10 +1260,12 @@ static void sci_dma_tx_complete(void *arg)
uart_xmit_advance(port, s->tx_dma_len);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (!uart_circ_empty(xmit)) {
+ s->tx_occurred = true;
+
+ if (!kfifo_is_empty(&tport->xmit_fifo)) {
s->cookie_tx = 0;
schedule_work(&s->work_tx);
} else {
@@ -1258,6 +1312,7 @@ static int sci_dma_rx_find_active(struct sci_port *s)
return -1;
}
+/* Must only be called with uart_port_lock taken */
static void sci_dma_rx_chan_invalidate(struct sci_port *s)
{
unsigned int i;
@@ -1271,9 +1326,14 @@ static void sci_dma_rx_chan_invalidate(struct sci_port *s)
static void sci_dma_rx_release(struct sci_port *s)
{
struct dma_chan *chan = s->chan_rx_saved;
+ struct uart_port *port = &s->port;
+ unsigned long flags;
+ uart_port_lock_irqsave(port, &flags);
s->chan_rx_saved = NULL;
sci_dma_rx_chan_invalidate(s);
+ uart_port_unlock_irqrestore(port, flags);
+
dmaengine_terminate_sync(chan);
dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0],
sg_dma_address(&s->sg_rx[0]));
@@ -1319,14 +1379,14 @@ static void sci_dma_rx_complete(void *arg)
dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line,
s->active_rx);
+ hrtimer_cancel(&s->rx_timer);
+
uart_port_lock_irqsave(port, &flags);
active = sci_dma_rx_find_active(s);
if (active >= 0)
count = sci_dma_rx_push(s, s->rx_buf[active], s->buf_len_rx);
- start_hrtimer_us(&s->rx_timer, s->rx_timeout);
-
if (count)
tty_flip_buffer_push(&port->state->port);
@@ -1349,17 +1409,18 @@ static void sci_dma_rx_complete(void *arg)
uart_port_unlock_irqrestore(port, flags);
dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n",
__func__, s->cookie_rx[active], active, s->active_rx);
+
+ start_hrtimer_us(&s->rx_timer, s->rx_timeout);
+
return;
fail:
- uart_port_unlock_irqrestore(port, flags);
- dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
/* Switch to PIO */
- uart_port_lock_irqsave(port, &flags);
dmaengine_terminate_async(chan);
sci_dma_rx_chan_invalidate(s);
sci_dma_rx_reenable_irq(s);
uart_port_unlock_irqrestore(port, flags);
+ dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n");
}
static void sci_dma_tx_release(struct sci_port *s)
@@ -1424,10 +1485,10 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = s->chan_tx;
struct uart_port *port = &s->port;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
unsigned long flags;
+ unsigned int tail;
dma_addr_t buf;
- int head, tail;
/*
* DMA is idle now.
@@ -1437,10 +1498,9 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
* consistent xmit buffer state.
*/
uart_port_lock_irq(port);
- head = xmit->head;
- tail = xmit->tail;
+ s->tx_dma_len = kfifo_out_linear(&tport->xmit_fifo, &tail,
+ UART_XMIT_SIZE);
buf = s->tx_dma_addr + tail;
- s->tx_dma_len = CIRC_CNT_TO_END(head, tail, UART_XMIT_SIZE);
if (!s->tx_dma_len) {
/* Transmit buffer has been flushed */
uart_port_unlock_irq(port);
@@ -1469,8 +1529,8 @@ static void sci_dma_tx_work_fn(struct work_struct *work)
}
uart_port_unlock_irq(port);
- dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n",
- __func__, xmit->buf, tail, head, s->cookie_tx);
+ dev_dbg(port->dev, "%s: %p: %u, cookie %d\n",
+ __func__, tport->xmit_buf, tail, s->cookie_tx);
dma_async_issue_pending(chan);
return;
@@ -1585,6 +1645,7 @@ static struct dma_chan *sci_request_dma_chan(struct uart_port *port,
static void sci_request_dma(struct uart_port *port)
{
struct sci_port *s = to_sci_port(port);
+ struct tty_port *tport = &port->state->port;
struct dma_chan *chan;
dev_dbg(port->dev, "%s: port %d\n", __func__, port->line);
@@ -1613,7 +1674,7 @@ static void sci_request_dma(struct uart_port *port)
if (chan) {
/* UART circular tx buffer is an aligned page. */
s->tx_dma_addr = dma_map_single(chan->device->dev,
- port->state->xmit.buf,
+ tport->xmit_buf,
UART_XMIT_SIZE,
DMA_TO_DEVICE);
if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) {
@@ -1622,7 +1683,7 @@ static void sci_request_dma(struct uart_port *port)
} else {
dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n",
__func__, UART_XMIT_SIZE,
- port->state->xmit.buf, &s->tx_dma_addr);
+ tport->xmit_buf, &s->tx_dma_addr);
INIT_WORK(&s->work_tx, sci_dma_tx_work_fn);
s->chan_tx_saved = s->chan_tx = chan;
@@ -1658,8 +1719,7 @@ static void sci_request_dma(struct uart_port *port)
dma += s->buf_len_rx;
}
- hrtimer_init(&s->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- s->rx_timer.function = sci_dma_rx_timer_fn;
+ hrtimer_setup(&s->rx_timer, sci_dma_rx_timer_fn, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
s->chan_rx_saved = s->chan_rx = chan;
@@ -1694,6 +1754,19 @@ static void sci_flush_buffer(struct uart_port *port)
s->cookie_tx = -EINVAL;
}
}
+
+static void sci_dma_check_tx_occurred(struct sci_port *s)
+{
+ struct dma_tx_state state;
+ enum dma_status status;
+
+ if (!s->chan_tx)
+ return;
+
+ status = dmaengine_tx_status(s->chan_tx, s->cookie_tx, &state);
+ if (status == DMA_COMPLETE || status == DMA_IN_PROGRESS)
+ s->tx_occurred = true;
+}
#else /* !CONFIG_SERIAL_SH_SCI_DMA */
static inline void sci_request_dma(struct uart_port *port)
{
@@ -1703,6 +1776,10 @@ static inline void sci_free_dma(struct uart_port *port)
{
}
+static void sci_dma_check_tx_occurred(struct sci_port *s)
+{
+}
+
#define sci_flush_buffer NULL
#endif /* !CONFIG_SERIAL_SH_SCI_DMA */
@@ -2039,6 +2116,12 @@ static unsigned int sci_tx_empty(struct uart_port *port)
{
unsigned short status = sci_serial_in(port, SCxSR);
unsigned short in_tx_fifo = sci_txfill(port);
+ struct sci_port *s = to_sci_port(port);
+
+ sci_dma_check_tx_occurred(s);
+
+ if (!s->tx_occurred)
+ return TIOCSER_TEMT;
return (status & SCxSR_TEND(port)) && !in_tx_fifo ? TIOCSER_TEMT : 0;
}
@@ -2118,8 +2201,9 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
if (!(mctrl & TIOCM_RTS)) {
/* Disable Auto RTS */
- sci_serial_out(port, SCFCR,
- sci_serial_in(port, SCFCR) & ~SCFCR_MCE);
+ if (s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE)
+ sci_serial_out(port, SCFCR,
+ sci_serial_in(port, SCFCR) & ~SCFCR_MCE);
/* Clear RTS */
sci_set_rts(port, 0);
@@ -2131,8 +2215,9 @@ static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl)
}
/* Enable Auto RTS */
- sci_serial_out(port, SCFCR,
- sci_serial_in(port, SCFCR) | SCFCR_MCE);
+ if (s->cfg->regtype != SCIx_RZV2H_SCIF_REGTYPE)
+ sci_serial_out(port, SCFCR,
+ sci_serial_in(port, SCFCR) | SCFCR_MCE);
} else {
/* Set RTS */
sci_set_rts(port, 1);
@@ -2208,6 +2293,7 @@ static int sci_startup(struct uart_port *port)
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
+ s->tx_occurred = false;
sci_request_dma(port);
ret = sci_request_irq(s);
@@ -2228,7 +2314,7 @@ static void sci_shutdown(struct uart_port *port)
dev_dbg(port->dev, "%s(%d)\n", __func__, port->line);
s->autorts = false;
- mctrl_gpio_disable_ms(to_sci_port(port)->gpios);
+ mctrl_gpio_disable_ms_sync(to_sci_port(port)->gpios);
uart_port_lock_irqsave(port, &flags);
sci_stop_rx(port);
@@ -2251,7 +2337,7 @@ static void sci_shutdown(struct uart_port *port)
#endif
if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0)
- del_timer_sync(&s->rx_fifo_timer);
+ timer_delete_sync(&s->rx_fifo_timer);
sci_free_irq(s);
sci_free_dma(port);
}
@@ -2988,10 +3074,6 @@ static int sci_init_single(struct platform_device *dev,
ret = sci_init_clocks(sci_port, &dev->dev);
if (ret < 0)
return ret;
-
- port->dev = &dev->dev;
-
- pm_runtime_enable(&dev->dev);
}
port->type = p->type;
@@ -3018,11 +3100,6 @@ static int sci_init_single(struct platform_device *dev,
return 0;
}
-static void sci_cleanup_single(struct sci_port *port)
-{
- pm_runtime_disable(port->port.dev);
-}
-
#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || \
defined(CONFIG_SERIAL_SH_SCI_EARLYCON)
static void serial_console_putchar(struct uart_port *port, unsigned char ch)
@@ -3192,8 +3269,6 @@ static void sci_remove(struct platform_device *dev)
sci_ports_in_use &= ~BIT(port->port.line);
uart_remove_one_port(&sci_uart_driver, &port->port);
- sci_cleanup_single(port);
-
if (port->port.fifosize > 1)
device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger);
if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF)
@@ -3219,6 +3294,10 @@ static const struct of_device_id of_sci_match[] __maybe_unused = {
.compatible = "renesas,scif-r9a07g044",
.data = SCI_OF_DATA(PORT_SCIF, SCIx_RZ_SCIFA_REGTYPE),
},
+ {
+ .compatible = "renesas,scif-r9a09g057",
+ .data = SCI_OF_DATA(PORT_SCIF, SCIx_RZV2H_SCIF_REGTYPE),
+ },
/* Family-specific types */
{
.compatible = "renesas,rcar-gen1-scif",
@@ -3311,6 +3390,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
}
sp = &sci_ports[id];
+ sp->rstc = rstc;
*dev_id = id;
p->type = SCI_OF_TYPE(data);
@@ -3324,7 +3404,8 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev,
static int sci_probe_single(struct platform_device *dev,
unsigned int index,
struct plat_sci_port *p,
- struct sci_port *sciport)
+ struct sci_port *sciport,
+ struct resource *sci_res)
{
int ret;
@@ -3353,6 +3434,11 @@ static int sci_probe_single(struct platform_device *dev,
if (ret)
return ret;
+ sciport->port.dev = &dev->dev;
+ ret = devm_pm_runtime_enable(&dev->dev);
+ if (ret)
+ return ret;
+
sciport->gpios = mctrl_gpio_init(&sciport->port, 0);
if (IS_ERR(sciport->gpios))
return PTR_ERR(sciport->gpios);
@@ -3366,18 +3452,37 @@ static int sci_probe_single(struct platform_device *dev,
sciport->port.flags |= UPF_HARD_FLOW;
}
- ret = uart_add_one_port(&sci_uart_driver, &sciport->port);
- if (ret) {
- sci_cleanup_single(sciport);
- return ret;
+ if (sci_uart_earlycon && sci_ports[0].port.mapbase == sci_res->start) {
+ /*
+ * In case:
+ * - this is the earlycon port (mapped on index 0 in sci_ports[]) and
+ * - it now maps to an alias other than zero and
+ * - the earlycon is still alive (e.g., "earlycon keep_bootcon" is
+ * available in bootargs)
+ *
+ * we need to avoid disabling clocks and PM domains through the runtime
+ * PM APIs called in __device_attach(). For this, increment the runtime
+ * PM reference counter (the clocks and PM domains were already enabled
+ * by the bootloader). Otherwise the earlycon may access the HW when it
+ * has no clocks enabled leading to failures (infinite loop in
+ * sci_poll_put_char()).
+ */
+ pm_runtime_get_noresume(&dev->dev);
+
+ /*
+ * Skip cleanup the sci_port[0] in early_console_exit(), this
+ * port is the same as the earlycon one.
+ */
+ sci_uart_earlycon_dev_probing = true;
}
- return 0;
+ return uart_add_one_port(&sci_uart_driver, &sciport->port);
}
static int sci_probe(struct platform_device *dev)
{
struct plat_sci_port *p;
+ struct resource *res;
struct sci_port *sp;
unsigned int dev_id;
int ret;
@@ -3407,9 +3512,29 @@ static int sci_probe(struct platform_device *dev)
}
sp = &sci_ports[dev_id];
+
+ /*
+ * In case:
+ * - the probed port alias is zero (as the one used by earlycon), and
+ * - the earlycon is still active (e.g., "earlycon keep_bootcon" in
+ * bootargs)
+ *
+ * defer the probe of this serial. This is a debug scenario and the user
+ * must be aware of it.
+ *
+ * Except when the probed port is the same as the earlycon port.
+ */
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ if (sci_uart_earlycon && sp == &sci_ports[0] && sp->port.mapbase != res->start)
+ return dev_err_probe(&dev->dev, -EBUSY, "sci_port[0] is used by earlycon!\n");
+
platform_set_drvdata(dev, sp);
- ret = sci_probe_single(dev, dev_id, p, sp);
+ ret = sci_probe_single(dev, dev_id, p, sp, res);
if (ret)
return ret;
@@ -3438,13 +3563,77 @@ static int sci_probe(struct platform_device *dev)
return 0;
}
+static void sci_console_save(struct sci_port *s)
+{
+ struct sci_suspend_regs *regs = &s->suspend_regs;
+ struct uart_port *port = &s->port;
+
+ if (sci_getreg(port, SCDL)->size)
+ regs->scdl = sci_serial_in(port, SCDL);
+ if (sci_getreg(port, SCCKS)->size)
+ regs->sccks = sci_serial_in(port, SCCKS);
+ if (sci_getreg(port, SCSMR)->size)
+ regs->scsmr = sci_serial_in(port, SCSMR);
+ if (sci_getreg(port, SCSCR)->size)
+ regs->scscr = sci_serial_in(port, SCSCR);
+ if (sci_getreg(port, SCFCR)->size)
+ regs->scfcr = sci_serial_in(port, SCFCR);
+ if (sci_getreg(port, SCSPTR)->size)
+ regs->scsptr = sci_serial_in(port, SCSPTR);
+ if (sci_getreg(port, SCBRR)->size)
+ regs->scbrr = sci_serial_in(port, SCBRR);
+ if (sci_getreg(port, HSSRR)->size)
+ regs->hssrr = sci_serial_in(port, HSSRR);
+ if (sci_getreg(port, SCPCR)->size)
+ regs->scpcr = sci_serial_in(port, SCPCR);
+ if (sci_getreg(port, SCPDR)->size)
+ regs->scpdr = sci_serial_in(port, SCPDR);
+ if (sci_getreg(port, SEMR)->size)
+ regs->semr = sci_serial_in(port, SEMR);
+}
+
+static void sci_console_restore(struct sci_port *s)
+{
+ struct sci_suspend_regs *regs = &s->suspend_regs;
+ struct uart_port *port = &s->port;
+
+ if (sci_getreg(port, SCDL)->size)
+ sci_serial_out(port, SCDL, regs->scdl);
+ if (sci_getreg(port, SCCKS)->size)
+ sci_serial_out(port, SCCKS, regs->sccks);
+ if (sci_getreg(port, SCSMR)->size)
+ sci_serial_out(port, SCSMR, regs->scsmr);
+ if (sci_getreg(port, SCSCR)->size)
+ sci_serial_out(port, SCSCR, regs->scscr);
+ if (sci_getreg(port, SCFCR)->size)
+ sci_serial_out(port, SCFCR, regs->scfcr);
+ if (sci_getreg(port, SCSPTR)->size)
+ sci_serial_out(port, SCSPTR, regs->scsptr);
+ if (sci_getreg(port, SCBRR)->size)
+ sci_serial_out(port, SCBRR, regs->scbrr);
+ if (sci_getreg(port, HSSRR)->size)
+ sci_serial_out(port, HSSRR, regs->hssrr);
+ if (sci_getreg(port, SCPCR)->size)
+ sci_serial_out(port, SCPCR, regs->scpcr);
+ if (sci_getreg(port, SCPDR)->size)
+ sci_serial_out(port, SCPDR, regs->scpdr);
+ if (sci_getreg(port, SEMR)->size)
+ sci_serial_out(port, SEMR, regs->semr);
+}
+
static __maybe_unused int sci_suspend(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
- if (sport)
+ if (sport) {
uart_suspend_port(&sci_uart_driver, &sport->port);
+ if (!console_suspend_enabled && uart_console(&sport->port))
+ sci_console_save(sport);
+ else
+ return reset_control_assert(sport->rstc);
+ }
+
return 0;
}
@@ -3452,8 +3641,18 @@ static __maybe_unused int sci_resume(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
- if (sport)
+ if (sport) {
+ if (!console_suspend_enabled && uart_console(&sport->port)) {
+ sci_console_restore(sport);
+ } else {
+ int ret = reset_control_deassert(sport->rstc);
+
+ if (ret)
+ return ret;
+ }
+
uart_resume_port(&sci_uart_driver, &sport->port);
+ }
return 0;
}
@@ -3462,7 +3661,7 @@ static SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume);
static struct platform_driver sci_driver = {
.probe = sci_probe,
- .remove_new = sci_remove,
+ .remove = sci_remove,
.driver = {
.name = "sh-sci",
.pm = &sci_dev_pm_ops,
@@ -3490,7 +3689,23 @@ sh_early_platform_init_buffer("earlyprintk", &sci_driver,
early_serial_buf, ARRAY_SIZE(early_serial_buf));
#endif
#ifdef CONFIG_SERIAL_SH_SCI_EARLYCON
-static struct plat_sci_port port_cfg __initdata;
+static struct plat_sci_port port_cfg;
+
+static int early_console_exit(struct console *co)
+{
+ struct sci_port *sci_port = &sci_ports[0];
+
+ /*
+ * Clean the slot used by earlycon. A new SCI device might
+ * map to this slot.
+ */
+ if (!sci_uart_earlycon_dev_probing) {
+ memset(sci_port, 0, sizeof(*sci_port));
+ sci_uart_earlycon = false;
+ }
+
+ return 0;
+}
static int __init early_console_setup(struct earlycon_device *device,
int type)
@@ -3499,15 +3714,18 @@ static int __init early_console_setup(struct earlycon_device *device,
return -ENODEV;
device->port.type = type;
- memcpy(&sci_ports[0].port, &device->port, sizeof(struct uart_port));
+ sci_ports[0].port = device->port;
port_cfg.type = type;
sci_ports[0].cfg = &port_cfg;
sci_ports[0].params = sci_probe_regmap(&port_cfg);
+ sci_uart_earlycon = true;
port_cfg.scscr = sci_serial_in(&sci_ports[0].port, SCSCR);
sci_serial_out(&sci_ports[0].port, SCSCR,
SCSCR_RE | SCSCR_TE | port_cfg.scscr);
device->con->write = serial_console_write;
+ device->con->exit = early_console_exit;
+
return 0;
}
static int __init sci_early_console_setup(struct earlycon_device *device,
@@ -3527,6 +3745,13 @@ static int __init rzscifa_early_console_setup(struct earlycon_device *device,
return early_console_setup(device, PORT_SCIF);
}
+static int __init rzv2hscif_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ port_cfg.regtype = SCIx_RZV2H_SCIF_REGTYPE;
+ return early_console_setup(device, PORT_SCIF);
+}
+
static int __init scifa_early_console_setup(struct earlycon_device *device,
const char *opt)
{
@@ -3547,6 +3772,7 @@ OF_EARLYCON_DECLARE(sci, "renesas,sci", sci_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif", scif_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif-r7s9210", rzscifa_early_console_setup);
OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a07g044", rzscifa_early_console_setup);
+OF_EARLYCON_DECLARE(scif, "renesas,scif-r9a09g057", rzv2hscif_early_console_setup);
OF_EARLYCON_DECLARE(scifa, "renesas,scifa", scifa_early_console_setup);
OF_EARLYCON_DECLARE(scifb, "renesas,scifb", scifb_early_console_setup);
OF_EARLYCON_DECLARE(hscif, "renesas,hscif", hscif_early_console_setup);
diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index 0670fd9f8496..054a8e630ace 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -563,8 +563,11 @@ static void sifive_serial_break_ctl(struct uart_port *port, int break_state)
static int sifive_serial_startup(struct uart_port *port)
{
struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
+ unsigned long flags;
+ uart_port_lock_irqsave(&ssp->port, &flags);
__ssp_enable_rxwm(ssp);
+ uart_port_unlock_irqrestore(&ssp->port, flags);
return 0;
}
@@ -572,9 +575,12 @@ static int sifive_serial_startup(struct uart_port *port)
static void sifive_serial_shutdown(struct uart_port *port)
{
struct sifive_serial_port *ssp = port_to_sifive_serial_port(port);
+ unsigned long flags;
+ uart_port_lock_irqsave(&ssp->port, &flags);
__ssp_disable_rxwm(ssp);
__ssp_disable_txwm(ssp);
+ uart_port_unlock_irqrestore(&ssp->port, flags);
}
/**
@@ -761,7 +767,7 @@ static int __init early_sifive_serial_setup(struct earlycon_device *dev,
}
OF_EARLYCON_DECLARE(sifive, "sifive,uart0", early_sifive_serial_setup);
-OF_EARLYCON_DECLARE(sifive, "sifive,fu540-c000-uart0",
+OF_EARLYCON_DECLARE(sifive, "sifive,fu540-c000-uart",
early_sifive_serial_setup);
#endif /* CONFIG_SERIAL_EARLYCON */
@@ -1032,7 +1038,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(sifive_uart_pm_ops, sifive_serial_suspend,
sifive_serial_resume);
static const struct of_device_id sifive_serial_of_match[] = {
- { .compatible = "sifive,fu540-c000-uart0" },
+ { .compatible = "sifive,fu540-c000-uart" },
{ .compatible = "sifive,uart0" },
{},
};
@@ -1040,7 +1046,7 @@ MODULE_DEVICE_TABLE(of, sifive_serial_of_match);
static struct platform_driver sifive_serial_platform_driver = {
.probe = sifive_serial_probe,
- .remove_new = sifive_serial_remove,
+ .remove = sifive_serial_remove,
.driver = {
.name = SIFIVE_SERIAL_NAME,
.pm = pm_sleep_ptr(&sifive_uart_pm_ops),
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
index 15f14fa593da..8c9366321f8e 100644
--- a/drivers/tty/serial/sprd_serial.c
+++ b/drivers/tty/serial/sprd_serial.c
@@ -53,10 +53,12 @@
#define SPRD_IEN_TX_EMPTY BIT(1)
#define SPRD_IEN_BREAK_DETECT BIT(7)
#define SPRD_IEN_TIMEOUT BIT(13)
+#define SPRD_IEN_DATA_TIMEOUT BIT(17)
/* interrupt clear register */
#define SPRD_ICLR 0x0014
#define SPRD_ICLR_TIMEOUT BIT(13)
+#define SPRD_ICLR_DATA_TIMEOUT BIT(17)
/* line control register */
#define SPRD_LCR 0x0018
@@ -102,6 +104,7 @@
#define SPRD_IMSR_TX_FIFO_EMPTY BIT(1)
#define SPRD_IMSR_BREAK_DETECT BIT(7)
#define SPRD_IMSR_TIMEOUT BIT(13)
+#define SPRD_IMSR_DATA_TIMEOUT BIT(17)
#define SPRD_DEFAULT_SOURCE_CLK 26000000
#define SPRD_RX_DMA_STEP 1
@@ -118,6 +121,12 @@ struct sprd_uart_dma {
bool enable;
};
+struct sprd_uart_data {
+ unsigned int timeout_ien;
+ unsigned int timeout_iclr;
+ unsigned int timeout_imsr;
+};
+
struct sprd_uart_port {
struct uart_port port;
char name[16];
@@ -126,6 +135,7 @@ struct sprd_uart_port {
struct sprd_uart_dma rx_dma;
dma_addr_t pos;
unsigned char *rx_buf_tail;
+ const struct sprd_uart_data *pdata;
};
static struct sprd_uart_port *sprd_port[UART_NR_MAX];
@@ -134,6 +144,18 @@ static int sprd_ports_num;
static int sprd_start_dma_rx(struct uart_port *port);
static int sprd_tx_dma_config(struct uart_port *port);
+static const struct sprd_uart_data sc9836_data = {
+ .timeout_ien = SPRD_IEN_TIMEOUT,
+ .timeout_iclr = SPRD_ICLR_TIMEOUT,
+ .timeout_imsr = SPRD_IMSR_TIMEOUT,
+};
+
+static const struct sprd_uart_data sc9632_data = {
+ .timeout_ien = SPRD_IEN_DATA_TIMEOUT,
+ .timeout_iclr = SPRD_ICLR_DATA_TIMEOUT,
+ .timeout_imsr = SPRD_IMSR_DATA_TIMEOUT,
+};
+
static inline unsigned int serial_in(struct uart_port *port,
unsigned int offset)
{
@@ -227,13 +249,13 @@ static int sprd_tx_buf_remap(struct uart_port *port)
{
struct sprd_uart_port *sp =
container_of(port, struct sprd_uart_port, port);
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
+ unsigned char *tail;
- sp->tx_dma.trans_len =
- CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ sp->tx_dma.trans_len = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
+ UART_XMIT_SIZE);
- sp->tx_dma.phys_addr = dma_map_single(port->dev,
- (void *)&(xmit->buf[xmit->tail]),
+ sp->tx_dma.phys_addr = dma_map_single(port->dev, tail,
sp->tx_dma.trans_len,
DMA_TO_DEVICE);
return dma_mapping_error(port->dev, sp->tx_dma.phys_addr);
@@ -244,7 +266,7 @@ static void sprd_complete_tx_dma(void *data)
struct uart_port *port = (struct uart_port *)data;
struct sprd_uart_port *sp =
container_of(port, struct sprd_uart_port, port);
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
unsigned long flags;
uart_port_lock_irqsave(port, &flags);
@@ -253,10 +275,10 @@ static void sprd_complete_tx_dma(void *data)
uart_xmit_advance(port, sp->tx_dma.trans_len);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit) || sprd_tx_buf_remap(port) ||
+ if (kfifo_is_empty(&tport->xmit_fifo) || sprd_tx_buf_remap(port) ||
sprd_tx_dma_config(port))
sp->tx_dma.trans_len = 0;
@@ -319,7 +341,7 @@ static void sprd_start_tx_dma(struct uart_port *port)
{
struct sprd_uart_port *sp =
container_of(port, struct sprd_uart_port, port);
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
if (port->x_char) {
serial_out(port, SPRD_TXD, port->x_char);
@@ -328,7 +350,7 @@ static void sprd_start_tx_dma(struct uart_port *port)
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
sprd_stop_tx_dma(port);
return;
}
@@ -637,6 +659,8 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
unsigned int ims;
+ struct sprd_uart_port *sp =
+ container_of(port, struct sprd_uart_port, port);
uart_port_lock(port);
@@ -647,14 +671,14 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
return IRQ_NONE;
}
- if (ims & SPRD_IMSR_TIMEOUT)
- serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT);
+ if (ims & sp->pdata->timeout_imsr)
+ serial_out(port, SPRD_ICLR, sp->pdata->timeout_iclr);
if (ims & SPRD_IMSR_BREAK_DETECT)
serial_out(port, SPRD_ICLR, SPRD_IMSR_BREAK_DETECT);
if (ims & (SPRD_IMSR_RX_FIFO_FULL | SPRD_IMSR_BREAK_DETECT |
- SPRD_IMSR_TIMEOUT))
+ sp->pdata->timeout_imsr))
sprd_rx(port);
if (ims & SPRD_IMSR_TX_FIFO_EMPTY)
@@ -729,7 +753,7 @@ static int sprd_startup(struct uart_port *port)
/* enable interrupt */
uart_port_lock_irqsave(port, &flags);
ien = serial_in(port, SPRD_IEN);
- ien |= SPRD_IEN_BREAK_DETECT | SPRD_IEN_TIMEOUT;
+ ien |= SPRD_IEN_BREAK_DETECT | sp->pdata->timeout_ien;
if (!sp->rx_dma.enable)
ien |= SPRD_IEN_RX_FULL;
serial_out(port, SPRD_IEN, ien);
@@ -1184,6 +1208,12 @@ static int sprd_probe(struct platform_device *pdev)
up->mapbase = res->start;
+ sport->pdata = of_device_get_match_data(&pdev->dev);
+ if (!sport->pdata) {
+ dev_err(&pdev->dev, "get match data failed!\n");
+ return -EINVAL;
+ }
+
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@@ -1248,14 +1278,15 @@ static int sprd_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(sprd_pm_ops, sprd_suspend, sprd_resume);
static const struct of_device_id serial_ids[] = {
- {.compatible = "sprd,sc9836-uart",},
+ {.compatible = "sprd,sc9836-uart", .data = &sc9836_data},
+ {.compatible = "sprd,sc9632-uart", .data = &sc9632_data},
{}
};
MODULE_DEVICE_TABLE(of, serial_ids);
static struct platform_driver sprd_platform_driver = {
.probe = sprd_probe,
- .remove_new = sprd_remove,
+ .remove = sprd_remove,
.driver = {
.name = "sprd_serial",
.of_match_table = serial_ids,
diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c
index a23e59551848..6ed9a327702b 100644
--- a/drivers/tty/serial/st-asc.c
+++ b/drivers/tty/serial/st-asc.c
@@ -387,9 +387,9 @@ static unsigned int asc_get_mctrl(struct uart_port *port)
/* There are probably characters waiting to be transmitted. */
static void asc_start_tx(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
- if (!uart_circ_empty(xmit))
+ if (!kfifo_is_empty(&tport->xmit_fifo))
asc_enable_tx_interrupts(port);
}
@@ -808,7 +808,6 @@ static void asc_serial_remove(struct platform_device *pdev)
uart_remove_one_port(&asc_uart_driver, port);
}
-#ifdef CONFIG_PM_SLEEP
static int asc_serial_suspend(struct device *dev)
{
struct uart_port *port = dev_get_drvdata(dev);
@@ -823,8 +822,6 @@ static int asc_serial_resume(struct device *dev)
return uart_resume_port(&asc_uart_driver, port);
}
-#endif /* CONFIG_PM_SLEEP */
-
/*----------------------------------------------------------------------*/
#ifdef CONFIG_SERIAL_ST_ASC_CONSOLE
@@ -932,16 +929,15 @@ static struct uart_driver asc_uart_driver = {
.cons = ASC_SERIAL_CONSOLE,
};
-static const struct dev_pm_ops asc_serial_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(asc_serial_suspend, asc_serial_resume)
-};
+static DEFINE_SIMPLE_DEV_PM_OPS(asc_serial_pm_ops, asc_serial_suspend,
+ asc_serial_resume);
static struct platform_driver asc_serial_driver = {
.probe = asc_serial_probe,
- .remove_new = asc_serial_remove,
+ .remove = asc_serial_remove,
.driver = {
.name = DRIVER_NAME,
- .pm = &asc_serial_pm_ops,
+ .pm = pm_sleep_ptr(&asc_serial_pm_ops),
.of_match_table = of_match_ptr(asc_match),
},
};
diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c
index 4fa5a03ebac0..ad06b760cfca 100644
--- a/drivers/tty/serial/stm32-usart.c
+++ b/drivers/tty/serial/stm32-usart.c
@@ -696,18 +696,23 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
+
+ while (1) {
+ unsigned char ch;
- while (!uart_circ_empty(xmit)) {
/* Check that TDR is empty before filling FIFO */
if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE))
break;
- writel_relaxed(xmit->buf[xmit->tail], port->membase + ofs->tdr);
- uart_xmit_advance(port, 1);
+
+ if (!uart_fifo_get(port, &ch))
+ break;
+
+ writel_relaxed(ch, port->membase + ofs->tdr);
}
/* rely on TXE irq (mask or unmask) for sending remaining data */
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
stm32_usart_tx_interrupt_disable(port);
else
stm32_usart_tx_interrupt_enable(port);
@@ -716,7 +721,7 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port)
static void stm32_usart_transmit_chars_dma(struct uart_port *port)
{
struct stm32_port *stm32port = to_stm32_port(port);
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
struct dma_async_tx_descriptor *desc = NULL;
unsigned int count;
int ret;
@@ -728,25 +733,8 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port)
return;
}
- count = uart_circ_chars_pending(xmit);
-
- if (count > TX_BUF_L)
- count = TX_BUF_L;
-
- if (xmit->tail < xmit->head) {
- memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], count);
- } else {
- size_t one = UART_XMIT_SIZE - xmit->tail;
- size_t two;
-
- if (one > count)
- one = count;
- two = count - one;
-
- memcpy(&stm32port->tx_buf[0], &xmit->buf[xmit->tail], one);
- if (two)
- memcpy(&stm32port->tx_buf[one], &xmit->buf[0], two);
- }
+ count = kfifo_out_peek(&tport->xmit_fifo, &stm32port->tx_buf[0],
+ TX_BUF_L);
desc = dmaengine_prep_slave_single(stm32port->tx_ch,
stm32port->tx_dma_buf,
@@ -792,14 +780,14 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
{
struct stm32_port *stm32_port = to_stm32_port(port);
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
u32 isr;
int ret;
if (!stm32_port->hw_flow_control &&
port->rs485.flags & SER_RS485_ENABLED &&
(port->x_char ||
- !(uart_circ_empty(xmit) || uart_tx_stopped(port)))) {
+ !(kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)))) {
stm32_usart_tc_interrupt_disable(port);
stm32_usart_rs485_rts_enable(port);
}
@@ -826,7 +814,7 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
stm32_usart_tx_interrupt_disable(port);
return;
}
@@ -841,10 +829,10 @@ static void stm32_usart_transmit_chars(struct uart_port *port)
else
stm32_usart_transmit_chars_pio(port);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit)) {
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
stm32_usart_tx_interrupt_disable(port);
if (!stm32_port->hw_flow_control &&
port->rs485.flags & SER_RS485_ENABLED) {
@@ -956,7 +944,7 @@ static void stm32_usart_enable_ms(struct uart_port *port)
static void stm32_usart_disable_ms(struct uart_port *port)
{
- mctrl_gpio_disable_ms(to_stm32_port(port)->gpios);
+ mctrl_gpio_disable_ms_sync(to_stm32_port(port)->gpios);
}
/* Transmit stop */
@@ -975,12 +963,10 @@ static void stm32_usart_stop_tx(struct uart_port *port)
/* There are probably characters waiting to be transmitted. */
static void stm32_usart_start_tx(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
- if (uart_circ_empty(xmit) && !port->x_char) {
- stm32_usart_rs485_rts_disable(port);
+ if (kfifo_is_empty(&tport->xmit_fifo) && !port->x_char)
return;
- }
stm32_usart_rs485_rts_enable(port);
@@ -1063,14 +1049,14 @@ static void stm32_usart_break_ctl(struct uart_port *port, int break_state)
const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs;
unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
+ uart_port_lock_irqsave(port, &flags);
if (break_state)
stm32_usart_set_bits(port, ofs->rqr, USART_RQR_SBKRQ);
else
stm32_usart_clr_bits(port, ofs->rqr, USART_RQR_SBKRQ);
- spin_unlock_irqrestore(&port->lock, flags);
+ uart_port_unlock_irqrestore(port, flags);
}
static int stm32_usart_startup(struct uart_port *port)
@@ -2200,7 +2186,7 @@ static const struct dev_pm_ops stm32_serial_pm_ops = {
static struct platform_driver stm32_serial_driver = {
.probe = stm32_usart_serial_probe,
- .remove_new = stm32_usart_serial_remove,
+ .remove = stm32_usart_serial_remove,
.driver = {
.name = DRIVER_NAME,
.pm = &stm32_serial_pm_ops,
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index 8d612ab80680..2b3ec65d595d 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -39,10 +39,13 @@ static char *con_read_page;
static int hung_up = 0;
-static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
+static void transmit_chars_putchar(struct uart_port *port,
+ struct tty_port *tport)
{
- while (!uart_circ_empty(xmit)) {
- long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
+ unsigned char ch;
+
+ while (kfifo_peek(&tport->xmit_fifo, &ch)) {
+ long status = sun4v_con_putchar(ch);
if (status != HV_EOK)
break;
@@ -51,14 +54,16 @@ static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit
}
}
-static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
+static void transmit_chars_write(struct uart_port *port, struct tty_port *tport)
{
- while (!uart_circ_empty(xmit)) {
- unsigned long ra = __pa(xmit->buf + xmit->tail);
- unsigned long len, status, sent;
+ while (!kfifo_is_empty(&tport->xmit_fifo)) {
+ unsigned long len, ra, status, sent;
+ unsigned char *tail;
+
+ len = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
+ UART_XMIT_SIZE);
+ ra = __pa(tail);
- len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
- UART_XMIT_SIZE);
status = sun4v_con_write(ra, len, &sent);
if (status != HV_EOK)
break;
@@ -165,7 +170,7 @@ static int receive_chars_read(struct uart_port *port)
}
struct sunhv_ops {
- void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
+ void (*transmit_chars)(struct uart_port *port, struct tty_port *tport);
int (*receive_chars)(struct uart_port *port);
};
@@ -196,18 +201,18 @@ static struct tty_port *receive_chars(struct uart_port *port)
static void transmit_chars(struct uart_port *port)
{
- struct circ_buf *xmit;
+ struct tty_port *tport;
if (!port->state)
return;
- xmit = &port->state->xmit;
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ tport = &port->state->port;
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))
return;
- sunhv_ops->transmit_chars(port, xmit);
+ sunhv_ops->transmit_chars(port, tport);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
}
@@ -628,7 +633,7 @@ static struct platform_driver hv_driver = {
.of_match_table = hv_match,
},
.probe = hv_probe,
- .remove_new = hv_remove,
+ .remove = hv_remove,
};
static int __init sunhv_init(void)
diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c
index f5e29eb4a4ce..38deee571b0d 100644
--- a/drivers/tty/serial/sunplus-uart.c
+++ b/drivers/tty/serial/sunplus-uart.c
@@ -200,7 +200,7 @@ static void sunplus_break_ctl(struct uart_port *port, int ctl)
static void transmit_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
if (port->x_char) {
sp_uart_put_char(port, port->x_char);
@@ -209,22 +209,24 @@ static void transmit_chars(struct uart_port *port)
return;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
sunplus_stop_tx(port);
return;
}
do {
- sp_uart_put_char(port, xmit->buf[xmit->tail]);
- uart_xmit_advance(port, 1);
- if (uart_circ_empty(xmit))
+ unsigned char ch;
+
+ if (!uart_fifo_get(port, &ch))
break;
+
+ sp_uart_put_char(port, ch);
} while (sunplus_tx_buf_not_full(port));
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
sunplus_stop_tx(port);
}
@@ -695,7 +697,7 @@ MODULE_DEVICE_TABLE(of, sp_uart_of_match);
static struct platform_driver sunplus_uart_platform_driver = {
.probe = sunplus_uart_probe,
- .remove_new = sunplus_uart_remove,
+ .remove = sunplus_uart_remove,
.driver = {
.name = "sunplus_uart",
.of_match_table = sp_uart_of_match,
diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c
index 1ea2f33a07a7..df906ccf2e8a 100644
--- a/drivers/tty/serial/sunsab.c
+++ b/drivers/tty/serial/sunsab.c
@@ -232,7 +232,7 @@ static void sunsab_tx_idle(struct uart_sunsab_port *);
static void transmit_chars(struct uart_sunsab_port *up,
union sab82532_irq_status *stat)
{
- struct circ_buf *xmit = &up->port.state->xmit;
+ struct tty_port *tport = &up->port.state->port;
int i;
if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) {
@@ -252,7 +252,7 @@ static void transmit_chars(struct uart_sunsab_port *up,
set_bit(SAB82532_XPR, &up->irqflags);
sunsab_tx_idle(up);
- if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(&up->port)) {
up->interrupt_mask1 |= SAB82532_IMR1_XPR;
writeb(up->interrupt_mask1, &up->regs->w.imr1);
return;
@@ -265,21 +265,22 @@ static void transmit_chars(struct uart_sunsab_port *up,
/* Stuff 32 bytes into Transmit FIFO. */
clear_bit(SAB82532_XPR, &up->irqflags);
for (i = 0; i < up->port.fifosize; i++) {
- writeb(xmit->buf[xmit->tail],
- &up->regs->w.xfifo[i]);
- uart_xmit_advance(&up->port, 1);
- if (uart_circ_empty(xmit))
+ unsigned char ch;
+
+ if (!uart_fifo_get(&up->port, &ch))
break;
+
+ writeb(ch, &up->regs->w.xfifo[i]);
}
/* Issue a Transmit Frame command. */
sunsab_cec_wait(up);
writeb(SAB82532_CMDR_XF, &up->regs->w.cmdr);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
sunsab_stop_tx(&up->port);
}
@@ -435,10 +436,10 @@ static void sunsab_start_tx(struct uart_port *port)
{
struct uart_sunsab_port *up =
container_of(port, struct uart_sunsab_port, port);
- struct circ_buf *xmit = &up->port.state->xmit;
+ struct tty_port *tport = &up->port.state->port;
int i;
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))
return;
up->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS|SAB82532_IMR1_XPR);
@@ -451,11 +452,12 @@ static void sunsab_start_tx(struct uart_port *port)
clear_bit(SAB82532_XPR, &up->irqflags);
for (i = 0; i < up->port.fifosize; i++) {
- writeb(xmit->buf[xmit->tail],
- &up->regs->w.xfifo[i]);
- uart_xmit_advance(&up->port, 1);
- if (uart_circ_empty(xmit))
+ unsigned char ch;
+
+ if (!uart_fifo_get(&up->port, &ch))
break;
+
+ writeb(ch, &up->regs->w.xfifo[i]);
}
/* Issue a Transmit Frame command. */
@@ -1098,7 +1100,7 @@ static struct platform_driver sab_driver = {
.of_match_table = sab_match,
},
.probe = sab_probe,
- .remove_new = sab_remove,
+ .remove = sab_remove,
};
static int __init sunsab_init(void)
diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index c8b65f4b2710..383141fe7ba0 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -151,16 +151,6 @@ static void serial_out(struct uart_sunsu_port *up, int offset, int value)
}
/*
- * We used to support using pause I/O for certain machines. We
- * haven't supported this for a while, but just in case it's badly
- * needed for certain old 386 machines, I've left these #define's
- * in....
- */
-#define serial_inp(up, offset) serial_in(up, offset)
-#define serial_outp(up, offset, value) serial_out(up, offset, value)
-
-
-/*
* For the 16C950
*/
static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value)
@@ -169,20 +159,6 @@ static void serial_icr_write(struct uart_sunsu_port *up, int offset, int value)
serial_out(up, UART_ICR, value);
}
-#if 0 /* Unused currently */
-static unsigned int serial_icr_read(struct uart_sunsu_port *up, int offset)
-{
- unsigned int value;
-
- serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
- serial_out(up, UART_SCR, offset);
- value = serial_in(up, UART_ICR);
- serial_icr_write(up, UART_ACR, up->acr);
-
- return value;
-}
-#endif
-
#ifdef CONFIG_SERIAL_8250_RSA
/*
* Attempts to turn on the RSA FIFO. Returns zero on failure.
@@ -193,12 +169,12 @@ static int __enable_rsa(struct uart_sunsu_port *up)
unsigned char mode;
int result;
- mode = serial_inp(up, UART_RSA_MSR);
+ mode = serial_in(up, UART_RSA_MSR);
result = mode & UART_RSA_MSR_FIFO;
if (!result) {
- serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
- mode = serial_inp(up, UART_RSA_MSR);
+ serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+ mode = serial_in(up, UART_RSA_MSR);
result = mode & UART_RSA_MSR_FIFO;
}
@@ -217,7 +193,7 @@ static void enable_rsa(struct uart_sunsu_port *up)
uart_port_unlock_irq(&up->port);
}
if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
- serial_outp(up, UART_RSA_FRR, 0);
+ serial_out(up, UART_RSA_FRR, 0);
}
}
@@ -236,12 +212,12 @@ static void disable_rsa(struct uart_sunsu_port *up)
up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
uart_port_lock_irq(&up->port);
- mode = serial_inp(up, UART_RSA_MSR);
+ mode = serial_in(up, UART_RSA_MSR);
result = !(mode & UART_RSA_MSR_FIFO);
if (!result) {
- serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
- mode = serial_inp(up, UART_RSA_MSR);
+ serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+ mode = serial_in(up, UART_RSA_MSR);
result = !(mode & UART_RSA_MSR_FIFO);
}
@@ -326,7 +302,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status)
int saw_console_brk = 0;
do {
- ch = serial_inp(up, UART_RX);
+ ch = serial_in(up, UART_RX);
flag = TTY_NORMAL;
up->port.icount.rx++;
@@ -387,7 +363,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status)
*/
tty_insert_flip_char(port, 0, TTY_OVERRUN);
ignore_char:
- *status = serial_inp(up, UART_LSR);
+ *status = serial_in(up, UART_LSR);
} while ((*status & UART_LSR_DR) && (max_count-- > 0));
if (saw_console_brk)
@@ -396,11 +372,12 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status)
static void transmit_chars(struct uart_sunsu_port *up)
{
- struct circ_buf *xmit = &up->port.state->xmit;
+ struct tty_port *tport = &up->port.state->port;
+ unsigned char ch;
int count;
if (up->port.x_char) {
- serial_outp(up, UART_TX, up->port.x_char);
+ serial_out(up, UART_TX, up->port.x_char);
up->port.icount.tx++;
up->port.x_char = 0;
return;
@@ -409,23 +386,23 @@ static void transmit_chars(struct uart_sunsu_port *up)
sunsu_stop_tx(&up->port);
return;
}
- if (uart_circ_empty(xmit)) {
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
__stop_tx(up);
return;
}
count = up->port.fifosize;
do {
- serial_out(up, UART_TX, xmit->buf[xmit->tail]);
- uart_xmit_advance(&up->port, 1);
- if (uart_circ_empty(xmit))
+ if (!uart_fifo_get(&up->port, &ch))
break;
+
+ serial_out(up, UART_TX, ch);
} while (--count > 0);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
__stop_tx(up);
}
@@ -459,7 +436,7 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
uart_port_lock_irqsave(&up->port, &flags);
do {
- status = serial_inp(up, UART_LSR);
+ status = serial_in(up, UART_LSR);
if (status & UART_LSR_DR)
receive_chars(up, &status);
check_modem_status(up);
@@ -497,7 +474,7 @@ static void sunsu_change_mouse_baud(struct uart_sunsu_port *up)
static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)
{
do {
- unsigned char ch = serial_inp(up, UART_RX);
+ unsigned char ch = serial_in(up, UART_RX);
/* Stop-A is handled by drivers/char/keyboard.c now. */
if (up->su_type == SU_PORT_KBD) {
@@ -529,7 +506,7 @@ static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id)
struct uart_sunsu_port *up = dev_id;
if (!(serial_in(up, UART_IIR) & UART_IIR_NO_INT)) {
- unsigned char status = serial_inp(up, UART_LSR);
+ unsigned char status = serial_in(up, UART_LSR);
if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0);
@@ -618,14 +595,14 @@ static int sunsu_startup(struct uart_port *port)
if (up->port.type == PORT_16C950) {
/* Wake up and initialize UART */
up->acr = 0;
- serial_outp(up, UART_LCR, 0xBF);
- serial_outp(up, UART_EFR, UART_EFR_ECB);
- serial_outp(up, UART_IER, 0);
- serial_outp(up, UART_LCR, 0);
+ serial_out(up, UART_LCR, 0xBF);
+ serial_out(up, UART_EFR, UART_EFR_ECB);
+ serial_out(up, UART_IER, 0);
+ serial_out(up, UART_LCR, 0);
serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
- serial_outp(up, UART_LCR, 0xBF);
- serial_outp(up, UART_EFR, UART_EFR_ECB);
- serial_outp(up, UART_LCR, 0);
+ serial_out(up, UART_LCR, 0xBF);
+ serial_out(up, UART_EFR, UART_EFR_ECB);
+ serial_out(up, UART_LCR, 0);
}
#ifdef CONFIG_SERIAL_8250_RSA
@@ -641,19 +618,19 @@ static int sunsu_startup(struct uart_port *port)
* (they will be reenabled in set_termios())
*/
if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) {
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
- serial_outp(up, UART_FCR, 0);
+ serial_out(up, UART_FCR, 0);
}
/*
* Clear the interrupt registers.
*/
- (void) serial_inp(up, UART_LSR);
- (void) serial_inp(up, UART_RX);
- (void) serial_inp(up, UART_IIR);
- (void) serial_inp(up, UART_MSR);
+ (void) serial_in(up, UART_LSR);
+ (void) serial_in(up, UART_RX);
+ (void) serial_in(up, UART_IIR);
+ (void) serial_in(up, UART_MSR);
/*
* At this point, there's no way the LSR could still be 0xff;
@@ -661,7 +638,7 @@ static int sunsu_startup(struct uart_port *port)
* here.
*/
if (!(up->port.flags & UPF_BUGGY_UART) &&
- (serial_inp(up, UART_LSR) == 0xff)) {
+ (serial_in(up, UART_LSR) == 0xff)) {
printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
return -ENODEV;
}
@@ -681,7 +658,7 @@ static int sunsu_startup(struct uart_port *port)
/*
* Now, initialize the UART
*/
- serial_outp(up, UART_LCR, UART_LCR_WLEN8);
+ serial_out(up, UART_LCR, UART_LCR_WLEN8);
uart_port_lock_irqsave(&up->port, &flags);
@@ -696,7 +673,7 @@ static int sunsu_startup(struct uart_port *port)
* anyway, so we don't enable them here.
*/
up->ier = UART_IER_RLSI | UART_IER_RDI;
- serial_outp(up, UART_IER, up->ier);
+ serial_out(up, UART_IER, up->ier);
if (up->port.flags & UPF_FOURPORT) {
unsigned int icp;
@@ -711,10 +688,10 @@ static int sunsu_startup(struct uart_port *port)
/*
* And clear the interrupt registers again for luck.
*/
- (void) serial_inp(up, UART_LSR);
- (void) serial_inp(up, UART_RX);
- (void) serial_inp(up, UART_IIR);
- (void) serial_inp(up, UART_MSR);
+ (void) serial_in(up, UART_LSR);
+ (void) serial_in(up, UART_RX);
+ (void) serial_in(up, UART_IIR);
+ (void) serial_in(up, UART_MSR);
return 0;
}
@@ -729,7 +706,7 @@ static void sunsu_shutdown(struct uart_port *port)
* Disable interrupts from this port
*/
up->ier = 0;
- serial_outp(up, UART_IER, 0);
+ serial_out(up, UART_IER, 0);
uart_port_lock_irqsave(&up->port, &flags);
if (up->port.flags & UPF_FOURPORT) {
@@ -745,11 +722,11 @@ static void sunsu_shutdown(struct uart_port *port)
/*
* Disable break condition and FIFOs
*/
- serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+ serial_out(up, UART_LCR, serial_in(up, UART_LCR) & ~UART_LCR_SBC);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT);
- serial_outp(up, UART_FCR, 0);
+ serial_out(up, UART_FCR, 0);
#ifdef CONFIG_SERIAL_8250_RSA
/*
@@ -871,22 +848,22 @@ sunsu_change_speed(struct uart_port *port, unsigned int cflag,
serial_out(up, UART_IER, up->ier);
if (uart_config[up->port.type].flags & UART_STARTECH) {
- serial_outp(up, UART_LCR, 0xBF);
- serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
+ serial_out(up, UART_LCR, 0xBF);
+ serial_out(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0);
}
- serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
- serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */
- serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */
+ serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
+ serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */
+ serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */
if (up->port.type == PORT_16750)
- serial_outp(up, UART_FCR, fcr); /* set fcr */
- serial_outp(up, UART_LCR, cval); /* reset DLAB */
+ serial_out(up, UART_FCR, fcr); /* set fcr */
+ serial_out(up, UART_LCR, cval); /* reset DLAB */
up->lcr = cval; /* Save LCR */
if (up->port.type != PORT_16750) {
if (fcr & UART_FCR_ENABLE_FIFO) {
/* emulated UARTs (Lucent Venus 167x) need two steps */
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
}
- serial_outp(up, UART_FCR, fcr); /* set fcr */
+ serial_out(up, UART_FCR, fcr); /* set fcr */
}
up->cflag = cflag;
@@ -1050,18 +1027,18 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
* 0x80 is a non-existent port; which should be safe since
* include/asm/io.h also makes this assumption.
*/
- scratch = serial_inp(up, UART_IER);
- serial_outp(up, UART_IER, 0);
+ scratch = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, 0);
#ifdef __i386__
outb(0xff, 0x080);
#endif
- scratch2 = serial_inp(up, UART_IER);
- serial_outp(up, UART_IER, 0x0f);
+ scratch2 = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, 0x0f);
#ifdef __i386__
outb(0, 0x080);
#endif
- scratch3 = serial_inp(up, UART_IER);
- serial_outp(up, UART_IER, scratch);
+ scratch3 = serial_in(up, UART_IER);
+ serial_out(up, UART_IER, scratch);
if (scratch2 != 0 || scratch3 != 0x0F)
goto out; /* We failed; there's nothing here */
}
@@ -1079,16 +1056,16 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
* that conflicts with COM 1-4 --- we hope!
*/
if (!(up->port.flags & UPF_SKIP_TEST)) {
- serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
- status1 = serial_inp(up, UART_MSR) & 0xF0;
- serial_outp(up, UART_MCR, save_mcr);
+ serial_out(up, UART_MCR, UART_MCR_LOOP | 0x0A);
+ status1 = serial_in(up, UART_MSR) & 0xF0;
+ serial_out(up, UART_MCR, save_mcr);
if (status1 != 0x90)
goto out; /* We failed loopback test */
}
- serial_outp(up, UART_LCR, 0xBF); /* set up for StarTech test */
- serial_outp(up, UART_EFR, 0); /* EFR is the same as FCR */
- serial_outp(up, UART_LCR, 0);
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_LCR, 0xBF); /* set up for StarTech test */
+ serial_out(up, UART_EFR, 0); /* EFR is the same as FCR */
+ serial_out(up, UART_LCR, 0);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
scratch = serial_in(up, UART_IIR) >> 6;
switch (scratch) {
case 0:
@@ -1106,19 +1083,19 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
}
if (up->port.type == PORT_16550A) {
/* Check for Startech UART's */
- serial_outp(up, UART_LCR, UART_LCR_DLAB);
+ serial_out(up, UART_LCR, UART_LCR_DLAB);
if (serial_in(up, UART_EFR) == 0) {
up->port.type = PORT_16650;
} else {
- serial_outp(up, UART_LCR, 0xBF);
+ serial_out(up, UART_LCR, 0xBF);
if (serial_in(up, UART_EFR) == 0)
up->port.type = PORT_16650V2;
}
}
if (up->port.type == PORT_16550A) {
/* Check for TI 16750 */
- serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB);
- serial_outp(up, UART_FCR,
+ serial_out(up, UART_LCR, save_lcr | UART_LCR_DLAB);
+ serial_out(up, UART_FCR,
UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
scratch = serial_in(up, UART_IIR) >> 5;
if (scratch == 7) {
@@ -1128,24 +1105,24 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
* mode if the UART_FCR7_64BYTE bit was set
* while UART_LCR_DLAB was latched.
*/
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
- serial_outp(up, UART_LCR, 0);
- serial_outp(up, UART_FCR,
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_LCR, 0);
+ serial_out(up, UART_FCR,
UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
scratch = serial_in(up, UART_IIR) >> 5;
if (scratch == 6)
up->port.type = PORT_16750;
}
- serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO);
}
- serial_outp(up, UART_LCR, save_lcr);
+ serial_out(up, UART_LCR, save_lcr);
if (up->port.type == PORT_16450) {
scratch = serial_in(up, UART_SCR);
- serial_outp(up, UART_SCR, 0xa5);
+ serial_out(up, UART_SCR, 0xa5);
status1 = serial_in(up, UART_SCR);
- serial_outp(up, UART_SCR, 0x5a);
+ serial_out(up, UART_SCR, 0x5a);
status2 = serial_in(up, UART_SCR);
- serial_outp(up, UART_SCR, scratch);
+ serial_out(up, UART_SCR, scratch);
if ((status1 != 0xa5) || (status2 != 0x5a))
up->port.type = PORT_8250;
@@ -1162,15 +1139,15 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
*/
#ifdef CONFIG_SERIAL_8250_RSA
if (up->port.type == PORT_RSA)
- serial_outp(up, UART_RSA_FRR, 0);
+ serial_out(up, UART_RSA_FRR, 0);
#endif
- serial_outp(up, UART_MCR, save_mcr);
- serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
+ serial_out(up, UART_MCR, save_mcr);
+ serial_out(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
- serial_outp(up, UART_FCR, 0);
+ serial_out(up, UART_FCR, 0);
(void)serial_in(up, UART_RX);
- serial_outp(up, UART_IER, 0);
+ serial_out(up, UART_IER, 0);
out:
uart_port_unlock_irqrestore(&up->port, flags);
@@ -1381,44 +1358,29 @@ static inline struct console *SUNSU_CONSOLE(void)
static enum su_type su_get_type(struct device_node *dp)
{
- struct device_node *ap = of_find_node_by_path("/aliases");
- enum su_type rc = SU_PORT_PORT;
+ struct device_node *ap __free(device_node) =
+ of_find_node_by_path("/aliases");
if (ap) {
const char *keyb = of_get_property(ap, "keyboard", NULL);
const char *ms = of_get_property(ap, "mouse", NULL);
- struct device_node *match;
if (keyb) {
- match = of_find_node_by_path(keyb);
+ struct device_node *match __free(device_node) =
+ of_find_node_by_path(keyb);
- /*
- * The pointer is used as an identifier not
- * as a pointer, we can drop the refcount on
- * the of__node immediately after getting it.
- */
- of_node_put(match);
-
- if (dp == match) {
- rc = SU_PORT_KBD;
- goto out;
- }
+ if (dp == match)
+ return SU_PORT_KBD;
}
if (ms) {
- match = of_find_node_by_path(ms);
-
- of_node_put(match);
+ struct device_node *match __free(device_node) =
+ of_find_node_by_path(ms);
- if (dp == match) {
- rc = SU_PORT_MS;
- goto out;
- }
+ if (dp == match)
+ return SU_PORT_MS;
}
}
-
-out:
- of_node_put(ap);
- return rc;
+ return SU_PORT_PORT;
}
static int su_probe(struct platform_device *op)
@@ -1563,7 +1525,7 @@ static struct platform_driver su_driver = {
.of_match_table = su_match,
},
.probe = su_probe,
- .remove_new = su_remove,
+ .remove = su_remove,
};
static int __init sunsu_init(void)
diff --git a/drivers/tty/serial/sunzilog.c b/drivers/tty/serial/sunzilog.c
index c99289c6c8f8..0551c24c06f5 100644
--- a/drivers/tty/serial/sunzilog.c
+++ b/drivers/tty/serial/sunzilog.c
@@ -453,7 +453,8 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up,
static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
struct zilog_channel __iomem *channel)
{
- struct circ_buf *xmit;
+ struct tty_port *tport;
+ unsigned char ch;
if (ZS_IS_CONS(up)) {
unsigned char status = readb(&channel->control);
@@ -496,21 +497,20 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
if (up->port.state == NULL)
goto ack_tx_int;
- xmit = &up->port.state->xmit;
- if (uart_circ_empty(xmit))
- goto ack_tx_int;
+ tport = &up->port.state->port;
if (uart_tx_stopped(&up->port))
goto ack_tx_int;
+ if (!uart_fifo_get(&up->port, &ch))
+ goto ack_tx_int;
+
up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
- writeb(xmit->buf[xmit->tail], &channel->data);
+ writeb(ch, &channel->data);
ZSDELAY();
ZS_WSYNC(channel);
- uart_xmit_advance(&up->port, 1);
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
return;
@@ -700,17 +700,16 @@ static void sunzilog_start_tx(struct uart_port *port)
port->icount.tx++;
port->x_char = 0;
} else {
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
+ unsigned char ch;
- if (uart_circ_empty(xmit))
+ if (!uart_fifo_get(&up->port, &ch))
return;
- writeb(xmit->buf[xmit->tail], &channel->data);
+ writeb(ch, &channel->data);
ZSDELAY();
ZS_WSYNC(channel);
- uart_xmit_advance(port, 1);
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&up->port);
}
}
@@ -1539,7 +1538,7 @@ static struct platform_driver zs_driver = {
.of_match_table = zs_match,
},
.probe = zs_probe,
- .remove_new = zs_remove,
+ .remove = zs_remove,
};
static int __init sunzilog_init(void)
diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c
index d9c78320eb02..7033dbfe8ba1 100644
--- a/drivers/tty/serial/tegra-tcu.c
+++ b/drivers/tty/serial/tegra-tcu.c
@@ -91,15 +91,17 @@ static void tegra_tcu_write(struct tegra_tcu *tcu, const char *s,
static void tegra_tcu_uart_start_tx(struct uart_port *port)
{
struct tegra_tcu *tcu = port->private_data;
- struct circ_buf *xmit = &port->state->xmit;
- unsigned long count;
+ struct tty_port *tport = &port->state->port;
+ unsigned char *tail;
+ unsigned int count;
for (;;) {
- count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ count = kfifo_out_linear_ptr(&tport->xmit_fifo, &tail,
+ UART_XMIT_SIZE);
if (!count)
break;
- tegra_tcu_write(tcu, &xmit->buf[xmit->tail], count);
+ tegra_tcu_write(tcu, tail, count);
uart_xmit_advance(port, count);
}
@@ -291,7 +293,7 @@ static struct platform_driver tegra_tcu_driver = {
.of_match_table = tegra_tcu_match,
},
.probe = tegra_tcu_probe,
- .remove_new = tegra_tcu_remove,
+ .remove = tegra_tcu_remove,
};
module_platform_driver(tegra_tcu_driver);
diff --git a/drivers/tty/serial/tegra-utc.c b/drivers/tty/serial/tegra-utc.c
new file mode 100644
index 000000000000..39b14fe813c9
--- /dev/null
+++ b/drivers/tty/serial/tegra-utc.c
@@ -0,0 +1,625 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
+// NVIDIA Tegra UTC (UART Trace Controller) driver.
+
+#include <linux/bits.h>
+#include <linux/console.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iopoll.h>
+#include <linux/kfifo.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/property.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/types.h>
+
+#define TEGRA_UTC_ENABLE 0x000
+#define TEGRA_UTC_ENABLE_CLIENT_ENABLE BIT(0)
+
+#define TEGRA_UTC_FIFO_THRESHOLD 0x008
+
+#define TEGRA_UTC_COMMAND 0x00c
+#define TEGRA_UTC_COMMAND_RESET BIT(0)
+#define TEGRA_UTC_COMMAND_FLUSH BIT(1)
+
+#define TEGRA_UTC_DATA 0x020
+
+#define TEGRA_UTC_FIFO_STATUS 0x100
+#define TEGRA_UTC_FIFO_EMPTY BIT(0)
+#define TEGRA_UTC_FIFO_FULL BIT(1)
+#define TEGRA_UTC_FIFO_REQ BIT(2)
+#define TEGRA_UTC_FIFO_OVERFLOW BIT(3)
+#define TEGRA_UTC_FIFO_TIMEOUT BIT(4)
+
+#define TEGRA_UTC_FIFO_OCCUPANCY 0x104
+
+#define TEGRA_UTC_INTR_STATUS 0x108
+#define TEGRA_UTC_INTR_SET 0x10c
+#define TEGRA_UTC_INTR_MASK 0x110
+#define TEGRA_UTC_INTR_CLEAR 0x114
+#define TEGRA_UTC_INTR_EMPTY BIT(0)
+#define TEGRA_UTC_INTR_FULL BIT(1)
+#define TEGRA_UTC_INTR_REQ BIT(2)
+#define TEGRA_UTC_INTR_OVERFLOW BIT(3)
+#define TEGRA_UTC_INTR_TIMEOUT BIT(4)
+
+#define TEGRA_UTC_UART_NR 16
+
+#define TEGRA_UTC_INTR_COMMON (TEGRA_UTC_INTR_REQ | TEGRA_UTC_INTR_FULL | TEGRA_UTC_INTR_EMPTY)
+
+struct tegra_utc_port {
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+ struct console console;
+#endif
+ struct uart_port port;
+
+ void __iomem *rx_base;
+ void __iomem *tx_base;
+
+ u32 tx_irqmask;
+ u32 rx_irqmask;
+
+ unsigned int fifosize;
+ u32 tx_threshold;
+ u32 rx_threshold;
+};
+
+static u32 tegra_utc_rx_readl(struct tegra_utc_port *tup, unsigned int offset)
+{
+ void __iomem *addr = tup->rx_base + offset;
+
+ return readl_relaxed(addr);
+}
+
+static void tegra_utc_rx_writel(struct tegra_utc_port *tup, u32 val, unsigned int offset)
+{
+ void __iomem *addr = tup->rx_base + offset;
+
+ writel_relaxed(val, addr);
+}
+
+static u32 tegra_utc_tx_readl(struct tegra_utc_port *tup, unsigned int offset)
+{
+ void __iomem *addr = tup->tx_base + offset;
+
+ return readl_relaxed(addr);
+}
+
+static void tegra_utc_tx_writel(struct tegra_utc_port *tup, u32 val, unsigned int offset)
+{
+ void __iomem *addr = tup->tx_base + offset;
+
+ writel_relaxed(val, addr);
+}
+
+static void tegra_utc_enable_tx_irq(struct tegra_utc_port *tup)
+{
+ tup->tx_irqmask = TEGRA_UTC_INTR_REQ;
+
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_MASK);
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_SET);
+}
+
+static void tegra_utc_disable_tx_irq(struct tegra_utc_port *tup)
+{
+ tup->tx_irqmask = 0x0;
+
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_MASK);
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_SET);
+}
+
+static void tegra_utc_stop_tx(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tegra_utc_disable_tx_irq(tup);
+}
+
+static void tegra_utc_init_tx(struct tegra_utc_port *tup)
+{
+ /* Disable TX. */
+ tegra_utc_tx_writel(tup, 0x0, TEGRA_UTC_ENABLE);
+
+ /* Update the FIFO Threshold. */
+ tegra_utc_tx_writel(tup, tup->tx_threshold, TEGRA_UTC_FIFO_THRESHOLD);
+
+ /* Clear and mask all the interrupts. */
+ tegra_utc_tx_writel(tup, TEGRA_UTC_INTR_COMMON, TEGRA_UTC_INTR_CLEAR);
+ tegra_utc_disable_tx_irq(tup);
+
+ /* Enable TX. */
+ tegra_utc_tx_writel(tup, TEGRA_UTC_ENABLE_CLIENT_ENABLE, TEGRA_UTC_ENABLE);
+}
+
+static void tegra_utc_init_rx(struct tegra_utc_port *tup)
+{
+ tup->rx_irqmask = TEGRA_UTC_INTR_REQ | TEGRA_UTC_INTR_TIMEOUT;
+
+ tegra_utc_rx_writel(tup, TEGRA_UTC_COMMAND_RESET, TEGRA_UTC_COMMAND);
+ tegra_utc_rx_writel(tup, tup->rx_threshold, TEGRA_UTC_FIFO_THRESHOLD);
+
+ /* Clear all the pending interrupts. */
+ tegra_utc_rx_writel(tup, TEGRA_UTC_INTR_TIMEOUT | TEGRA_UTC_INTR_OVERFLOW |
+ TEGRA_UTC_INTR_COMMON, TEGRA_UTC_INTR_CLEAR);
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_MASK);
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_SET);
+
+ /* Enable RX. */
+ tegra_utc_rx_writel(tup, TEGRA_UTC_ENABLE_CLIENT_ENABLE, TEGRA_UTC_ENABLE);
+}
+
+static bool tegra_utc_tx_chars(struct tegra_utc_port *tup)
+{
+ struct uart_port *port = &tup->port;
+ unsigned int pending;
+ u8 c;
+
+ pending = uart_port_tx(port, c,
+ !(tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_STATUS) & TEGRA_UTC_FIFO_FULL),
+ tegra_utc_tx_writel(tup, c, TEGRA_UTC_DATA));
+
+ return pending;
+}
+
+static void tegra_utc_rx_chars(struct tegra_utc_port *tup)
+{
+ struct tty_port *port = &tup->port.state->port;
+ unsigned int max_chars = 256;
+ u32 status;
+ int sysrq;
+ u32 ch;
+
+ while (max_chars--) {
+ status = tegra_utc_rx_readl(tup, TEGRA_UTC_FIFO_STATUS);
+ if (status & TEGRA_UTC_FIFO_EMPTY)
+ break;
+
+ ch = tegra_utc_rx_readl(tup, TEGRA_UTC_DATA);
+ tup->port.icount.rx++;
+
+ if (status & TEGRA_UTC_FIFO_OVERFLOW)
+ tup->port.icount.overrun++;
+
+ uart_port_unlock(&tup->port);
+ sysrq = uart_handle_sysrq_char(&tup->port, ch);
+ uart_port_lock(&tup->port);
+
+ if (!sysrq)
+ tty_insert_flip_char(port, ch, TTY_NORMAL);
+ }
+
+ tty_flip_buffer_push(port);
+}
+
+static irqreturn_t tegra_utc_isr(int irq, void *dev_id)
+{
+ struct tegra_utc_port *tup = dev_id;
+ unsigned int handled = 0;
+ u32 status;
+
+ uart_port_lock(&tup->port);
+
+ /* Process RX_REQ and RX_TIMEOUT interrupts. */
+ do {
+ status = tegra_utc_rx_readl(tup, TEGRA_UTC_INTR_STATUS) & tup->rx_irqmask;
+ if (status) {
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_CLEAR);
+ tegra_utc_rx_chars(tup);
+ handled = 1;
+ }
+ } while (status);
+
+ /* Process TX_REQ interrupt. */
+ do {
+ status = tegra_utc_tx_readl(tup, TEGRA_UTC_INTR_STATUS) & tup->tx_irqmask;
+ if (status) {
+ tegra_utc_tx_writel(tup, tup->tx_irqmask, TEGRA_UTC_INTR_CLEAR);
+ tegra_utc_tx_chars(tup);
+ handled = 1;
+ }
+ } while (status);
+
+ uart_port_unlock(&tup->port);
+
+ return IRQ_RETVAL(handled);
+}
+
+static unsigned int tegra_utc_tx_empty(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ return tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_OCCUPANCY) ? 0 : TIOCSER_TEMT;
+}
+
+static void tegra_utc_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int tegra_utc_get_mctrl(struct uart_port *port)
+{
+ return 0;
+}
+
+static void tegra_utc_start_tx(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ if (tegra_utc_tx_chars(tup))
+ tegra_utc_enable_tx_irq(tup);
+}
+
+static void tegra_utc_stop_rx(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tup->rx_irqmask = 0x0;
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_MASK);
+ tegra_utc_rx_writel(tup, tup->rx_irqmask, TEGRA_UTC_INTR_SET);
+}
+
+static void tegra_utc_hw_init(struct tegra_utc_port *tup)
+{
+ tegra_utc_init_tx(tup);
+ tegra_utc_init_rx(tup);
+}
+
+static int tegra_utc_startup(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+ int ret;
+
+ tegra_utc_hw_init(tup);
+
+ /* Interrupt is dedicated to this UTC client. */
+ ret = request_irq(port->irq, tegra_utc_isr, 0, dev_name(port->dev), tup);
+ if (ret < 0)
+ dev_err(port->dev, "failed to register interrupt handler\n");
+
+ return ret;
+}
+
+static void tegra_utc_shutdown(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tegra_utc_rx_writel(tup, 0x0, TEGRA_UTC_ENABLE);
+ free_irq(port->irq, tup);
+}
+
+static void tegra_utc_set_termios(struct uart_port *port, struct ktermios *termios,
+ const struct ktermios *old)
+{
+ /* The Tegra UTC clients supports only 8-N-1 configuration without HW flow control */
+ termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
+ termios->c_cflag &= ~(CMSPAR | CRTSCTS);
+ termios->c_cflag |= CS8 | CLOCAL;
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+
+static int tegra_utc_poll_init(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tegra_utc_hw_init(tup);
+ return 0;
+}
+
+static int tegra_utc_get_poll_char(struct uart_port *port)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ if (tegra_utc_rx_readl(tup, TEGRA_UTC_FIFO_STATUS) & TEGRA_UTC_FIFO_EMPTY)
+ return NO_POLL_CHAR;
+
+ return tegra_utc_rx_readl(tup, TEGRA_UTC_DATA);
+}
+
+static void tegra_utc_put_poll_char(struct uart_port *port, unsigned char ch)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+ u32 val;
+
+ read_poll_timeout_atomic(tegra_utc_tx_readl, val, !(val & TEGRA_UTC_FIFO_FULL),
+ 0, USEC_PER_SEC, false, tup, TEGRA_UTC_FIFO_STATUS);
+
+ tegra_utc_tx_writel(tup, ch, TEGRA_UTC_DATA);
+}
+
+#endif
+
+static const struct uart_ops tegra_utc_uart_ops = {
+ .tx_empty = tegra_utc_tx_empty,
+ .set_mctrl = tegra_utc_set_mctrl,
+ .get_mctrl = tegra_utc_get_mctrl,
+ .stop_tx = tegra_utc_stop_tx,
+ .start_tx = tegra_utc_start_tx,
+ .stop_rx = tegra_utc_stop_rx,
+ .startup = tegra_utc_startup,
+ .shutdown = tegra_utc_shutdown,
+ .set_termios = tegra_utc_set_termios,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_init = tegra_utc_poll_init,
+ .poll_get_char = tegra_utc_get_poll_char,
+ .poll_put_char = tegra_utc_put_poll_char,
+#endif
+};
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+#define TEGRA_UTC_DEFAULT_FIFO_THRESHOLD 4
+#define TEGRA_UTC_EARLYCON_MAX_BURST_SIZE 128
+
+static void tegra_utc_putc(struct uart_port *port, unsigned char c)
+{
+ writel(c, port->membase + TEGRA_UTC_DATA);
+}
+
+static void tegra_utc_early_write(struct console *con, const char *s, unsigned int n)
+{
+ struct earlycon_device *dev = con->data;
+
+ while (n) {
+ u32 burst_size = TEGRA_UTC_EARLYCON_MAX_BURST_SIZE;
+
+ burst_size -= readl(dev->port.membase + TEGRA_UTC_FIFO_OCCUPANCY);
+ if (n < burst_size)
+ burst_size = n;
+
+ uart_console_write(&dev->port, s, burst_size, tegra_utc_putc);
+
+ n -= burst_size;
+ s += burst_size;
+ }
+}
+
+static int __init tegra_utc_early_console_setup(struct earlycon_device *device, const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ /* Configure TX */
+ writel(TEGRA_UTC_COMMAND_FLUSH | TEGRA_UTC_COMMAND_RESET,
+ device->port.membase + TEGRA_UTC_COMMAND);
+ writel(TEGRA_UTC_DEFAULT_FIFO_THRESHOLD, device->port.membase + TEGRA_UTC_FIFO_THRESHOLD);
+
+ /* Clear and mask all the interrupts. */
+ writel(TEGRA_UTC_INTR_COMMON, device->port.membase + TEGRA_UTC_INTR_CLEAR);
+
+ writel(0x0, device->port.membase + TEGRA_UTC_INTR_MASK);
+ writel(0x0, device->port.membase + TEGRA_UTC_INTR_SET);
+
+ /* Enable TX. */
+ writel(TEGRA_UTC_ENABLE_CLIENT_ENABLE, device->port.membase + TEGRA_UTC_ENABLE);
+
+ device->con->write = tegra_utc_early_write;
+
+ return 0;
+}
+OF_EARLYCON_DECLARE(tegra_utc, "nvidia,tegra264-utc", tegra_utc_early_console_setup);
+
+static void tegra_utc_console_putchar(struct uart_port *port, unsigned char ch)
+{
+ struct tegra_utc_port *tup = container_of(port, struct tegra_utc_port, port);
+
+ tegra_utc_tx_writel(tup, ch, TEGRA_UTC_DATA);
+}
+
+static void tegra_utc_console_write_atomic(struct console *cons, struct nbcon_write_context *wctxt)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+ unsigned int len;
+ char *outbuf;
+
+ if (!nbcon_enter_unsafe(wctxt))
+ return;
+
+ outbuf = wctxt->outbuf;
+ len = wctxt->len;
+
+ while (len) {
+ u32 burst_size = tup->fifosize;
+
+ burst_size -= tegra_utc_tx_readl(tup, TEGRA_UTC_FIFO_OCCUPANCY);
+ if (len < burst_size)
+ burst_size = len;
+
+ uart_console_write(&tup->port, outbuf, burst_size, tegra_utc_console_putchar);
+
+ outbuf += burst_size;
+ len -= burst_size;
+ };
+
+ nbcon_exit_unsafe(wctxt);
+}
+
+static void tegra_utc_console_write_thread(struct console *cons, struct nbcon_write_context *wctxt)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+ unsigned int len = READ_ONCE(wctxt->len);
+ unsigned int i;
+ u32 val;
+
+ for (i = 0; i < len; i++) {
+ if (!nbcon_enter_unsafe(wctxt))
+ break;
+
+ read_poll_timeout_atomic(tegra_utc_tx_readl, val, !(val & TEGRA_UTC_FIFO_FULL),
+ 0, USEC_PER_SEC, false, tup, TEGRA_UTC_FIFO_STATUS);
+ uart_console_write(&tup->port, wctxt->outbuf + i, 1, tegra_utc_console_putchar);
+
+ if (!nbcon_exit_unsafe(wctxt))
+ break;
+ }
+}
+
+static void tegra_utc_console_device_lock(struct console *cons, unsigned long *flags)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+ struct uart_port *port = &tup->port;
+
+ __uart_port_lock_irqsave(port, flags);
+}
+
+static void tegra_utc_console_device_unlock(struct console *cons, unsigned long flags)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+ struct uart_port *port = &tup->port;
+
+ __uart_port_unlock_irqrestore(port, flags);
+}
+
+static int tegra_utc_console_setup(struct console *cons, char *options)
+{
+ struct tegra_utc_port *tup = container_of(cons, struct tegra_utc_port, console);
+
+ tegra_utc_init_tx(tup);
+
+ return 0;
+}
+#endif
+
+static struct uart_driver tegra_utc_driver = {
+ .driver_name = "tegra-utc",
+ .dev_name = "ttyUTC",
+ .nr = TEGRA_UTC_UART_NR,
+};
+
+static int tegra_utc_setup_port(struct device *dev, struct tegra_utc_port *tup)
+{
+ tup->port.dev = dev;
+ tup->port.fifosize = tup->fifosize;
+ tup->port.flags = UPF_BOOT_AUTOCONF;
+ tup->port.iotype = UPIO_MEM;
+ tup->port.ops = &tegra_utc_uart_ops;
+ tup->port.type = PORT_TEGRA_TCU;
+ tup->port.private_data = tup;
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+ strscpy(tup->console.name, "ttyUTC", sizeof(tup->console.name));
+ tup->console.write_atomic = tegra_utc_console_write_atomic;
+ tup->console.write_thread = tegra_utc_console_write_thread;
+ tup->console.device_lock = tegra_utc_console_device_lock;
+ tup->console.device_unlock = tegra_utc_console_device_unlock;
+ tup->console.device = uart_console_device;
+ tup->console.setup = tegra_utc_console_setup;
+ tup->console.flags = CON_PRINTBUFFER | CON_NBCON;
+ tup->console.data = &tegra_utc_driver;
+#endif
+
+ return uart_read_port_properties(&tup->port);
+}
+
+static int tegra_utc_register_port(struct tegra_utc_port *tup)
+{
+ int ret;
+
+ ret = uart_add_one_port(&tegra_utc_driver, &tup->port);
+ if (ret)
+ return ret;
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+ register_console(&tup->console);
+#endif
+
+ return 0;
+}
+
+static int tegra_utc_probe(struct platform_device *pdev)
+{
+ const unsigned int *soc_fifosize;
+ struct device *dev = &pdev->dev;
+ struct tegra_utc_port *tup;
+ int ret;
+
+ tup = devm_kzalloc(dev, sizeof(*tup), GFP_KERNEL);
+ if (!tup)
+ return -ENOMEM;
+
+ ret = device_property_read_u32(dev, "tx-threshold", &tup->tx_threshold);
+ if (ret)
+ return dev_err_probe(dev, ret, "missing %s property\n", "tx-threshold");
+
+ ret = device_property_read_u32(dev, "rx-threshold", &tup->rx_threshold);
+ if (ret)
+ return dev_err_probe(dev, ret, "missing %s property\n", "rx-threshold");
+
+ soc_fifosize = device_get_match_data(dev);
+ tup->fifosize = *soc_fifosize;
+
+ tup->tx_base = devm_platform_ioremap_resource_byname(pdev, "tx");
+ if (IS_ERR(tup->tx_base))
+ return PTR_ERR(tup->tx_base);
+
+ tup->rx_base = devm_platform_ioremap_resource_byname(pdev, "rx");
+ if (IS_ERR(tup->rx_base))
+ return PTR_ERR(tup->rx_base);
+
+ ret = tegra_utc_setup_port(dev, tup);
+ if (ret)
+ dev_err_probe(dev, ret, "failed to setup uart port\n");
+
+ platform_set_drvdata(pdev, tup);
+
+ return tegra_utc_register_port(tup);
+}
+
+static void tegra_utc_remove(struct platform_device *pdev)
+{
+ struct tegra_utc_port *tup = platform_get_drvdata(pdev);
+
+#if IS_ENABLED(CONFIG_SERIAL_TEGRA_UTC_CONSOLE)
+ unregister_console(&tup->console);
+#endif
+ uart_remove_one_port(&tegra_utc_driver, &tup->port);
+}
+
+static const unsigned int tegra264_utc_soc = 128;
+
+static const struct of_device_id tegra_utc_of_match[] = {
+ { .compatible = "nvidia,tegra264-utc", .data = &tegra264_utc_soc },
+ {}
+};
+MODULE_DEVICE_TABLE(of, tegra_utc_of_match);
+
+static struct platform_driver tegra_utc_platform_driver = {
+ .probe = tegra_utc_probe,
+ .remove = tegra_utc_remove,
+ .driver = {
+ .name = "tegra-utc",
+ .of_match_table = tegra_utc_of_match,
+ },
+};
+
+static int __init tegra_utc_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&tegra_utc_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&tegra_utc_platform_driver);
+ if (ret)
+ uart_unregister_driver(&tegra_utc_driver);
+
+ return ret;
+}
+module_init(tegra_utc_init);
+
+static void __exit tegra_utc_exit(void)
+{
+ platform_driver_unregister(&tegra_utc_platform_driver);
+ uart_unregister_driver(&tegra_utc_driver);
+}
+module_exit(tegra_utc_exit);
+
+MODULE_AUTHOR("Kartik Rajput <kkartik@nvidia.com>");
+MODULE_DESCRIPTION("Tegra UART Trace Controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/timbuart.c b/drivers/tty/serial/timbuart.c
index 4bc89a9b380a..6fa93c3872a7 100644
--- a/drivers/tty/serial/timbuart.c
+++ b/drivers/tty/serial/timbuart.c
@@ -95,14 +95,11 @@ static void timbuart_rx_chars(struct uart_port *port)
static void timbuart_tx_chars(struct uart_port *port)
{
- struct circ_buf *xmit = &port->state->xmit;
+ unsigned char ch;
while (!(ioread32(port->membase + TIMBUART_ISR) & TXBF) &&
- !uart_circ_empty(xmit)) {
- iowrite8(xmit->buf[xmit->tail],
- port->membase + TIMBUART_TXFIFO);
- uart_xmit_advance(port, 1);
- }
+ uart_fifo_get(port, &ch))
+ iowrite8(ch, port->membase + TIMBUART_TXFIFO);
dev_dbg(port->dev,
"%s - total written %d bytes, CTL: %x, RTS: %x, baud: %x\n",
@@ -117,9 +114,9 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
{
struct timbuart_port *uart =
container_of(port, struct timbuart_port, port);
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))
return;
if (port->x_char)
@@ -130,7 +127,7 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
/* clear all TX interrupts */
iowrite32(TXFLAGS, port->membase + TIMBUART_ISR);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
} else
/* Re-enable any tx interrupt */
@@ -141,7 +138,7 @@ static void timbuart_handle_tx_port(struct uart_port *port, u32 isr, u32 *ier)
* we wake up the upper layer later when we got the interrupt
* to give it some time to go out...
*/
- if (!uart_circ_empty(xmit))
+ if (!kfifo_is_empty(&tport->xmit_fifo))
*ier |= TXBAE;
dev_dbg(port->dev, "%s - leaving\n", __func__);
@@ -488,7 +485,7 @@ static struct platform_driver timbuart_platform_driver = {
.name = "timb-uart",
},
.probe = timbuart_probe,
- .remove_new = timbuart_remove,
+ .remove = timbuart_remove,
};
module_platform_driver(timbuart_platform_driver);
diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c
index 10ba41b7be99..a41e7fc373b7 100644
--- a/drivers/tty/serial/uartlite.c
+++ b/drivers/tty/serial/uartlite.c
@@ -189,7 +189,8 @@ static int ulite_receive(struct uart_port *port, int stat)
static int ulite_transmit(struct uart_port *port, int stat)
{
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
+ unsigned char ch;
if (stat & ULITE_STATUS_TXFULL)
return 0;
@@ -201,14 +202,16 @@ static int ulite_transmit(struct uart_port *port, int stat)
return 1;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+ if (uart_tx_stopped(port))
+ return 0;
+
+ if (!uart_fifo_get(port, &ch))
return 0;
- uart_out32(xmit->buf[xmit->tail], ULITE_TX, port);
- uart_xmit_advance(port, 1);
+ uart_out32(ch, ULITE_TX, port);
/* wake up */
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
return 1;
@@ -912,7 +915,7 @@ MODULE_ALIAS("platform:uartlite");
static struct platform_driver ulite_platform_driver = {
.probe = ulite_probe,
- .remove_new = ulite_remove,
+ .remove = ulite_remove,
.driver = {
.name = "uartlite",
.of_match_table = of_match_ptr(ulite_of_match),
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index 397b95dff7ed..0613f8c11ab1 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -334,7 +334,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
unsigned char *p;
unsigned int count;
struct uart_port *port = &qe_port->port;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
/* Handle xon/xoff */
if (port->x_char) {
@@ -358,7 +358,7 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
return 1;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
qe_uart_stop_tx(port);
return 0;
}
@@ -366,16 +366,10 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
/* Pick next descriptor and fill from buffer */
bdp = qe_port->tx_cur;
- while (!(ioread16be(&bdp->status) & BD_SC_READY) && !uart_circ_empty(xmit)) {
- count = 0;
+ while (!(ioread16be(&bdp->status) & BD_SC_READY) &&
+ !kfifo_is_empty(&tport->xmit_fifo)) {
p = qe2cpu_addr(ioread32be(&bdp->buf), qe_port);
- while (count < qe_port->tx_fifosize) {
- *p++ = xmit->buf[xmit->tail];
- uart_xmit_advance(port, 1);
- count++;
- if (uart_circ_empty(xmit))
- break;
- }
+ count = uart_fifo_out(port, p, qe_port->tx_fifosize);
iowrite16be(count, &bdp->length);
qe_setbits_be16(&bdp->status, BD_SC_READY);
@@ -388,10 +382,10 @@ static int qe_uart_tx_pump(struct uart_qe_port *qe_port)
}
qe_port->tx_cur = bdp;
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit)) {
+ if (kfifo_is_empty(&tport->xmit_fifo)) {
/* The kernel buffer is empty, so turn off TX interrupts. We
don't need to be told when the QE is finished transmitting
the data. */
@@ -1051,7 +1045,7 @@ static int qe_uart_verify_port(struct uart_port *port,
if (ser->type != PORT_UNKNOWN && ser->type != PORT_CPM)
return -EINVAL;
- if (ser->irq < 0 || ser->irq >= nr_irqs)
+ if (ser->irq < 0 || ser->irq >= irq_get_nr_irqs())
return -EINVAL;
if (ser->baud_base < 9600)
@@ -1490,7 +1484,7 @@ static struct platform_driver ucc_uart_of_driver = {
.of_match_table = ucc_uart_match,
},
.probe = ucc_uart_probe,
- .remove_new = ucc_uart_remove,
+ .remove = ucc_uart_remove,
};
static int __init ucc_uart_init(void)
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 5f48ec37cb25..fe457bf1e15b 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -25,6 +25,7 @@
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
+#include <linux/reset.h>
#define CDNS_UART_TTY_NAME "ttyPS"
#define CDNS_UART_NAME "xuartps"
@@ -198,6 +199,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255");
* @gpiod_rts: Pointer to the gpio descriptor
* @rs485_tx_started: RS485 tx state
* @tx_timer: Timer for tx
+ * @rstc: Pointer to the reset control
*/
struct cdns_uart {
struct uart_port *port;
@@ -211,12 +213,13 @@ struct cdns_uart {
struct gpio_desc *gpiod_rts;
bool rs485_tx_started;
struct hrtimer tx_timer;
+ struct reset_control *rstc;
};
struct cdns_platform_data {
u32 quirks;
};
-struct serial_rs485 cdns_rs485_supported = {
+static struct serial_rs485 cdns_rs485_supported = {
.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
SER_RS485_RTS_AFTER_SEND,
.delay_rts_before_send = 1,
@@ -284,7 +287,7 @@ static void cdns_uart_handle_rx(void *dev_id, unsigned int isrstatus)
continue;
}
- if (uart_handle_sysrq_char(port, data))
+ if (uart_prepare_sysrq_char(port, data))
continue;
if (is_rxbs_support) {
@@ -425,33 +428,33 @@ static void cdns_uart_handle_tx(void *dev_id)
{
struct uart_port *port = (struct uart_port *)dev_id;
struct cdns_uart *cdns_uart = port->private_data;
- struct circ_buf *xmit = &port->state->xmit;
+ struct tty_port *tport = &port->state->port;
unsigned int numbytes;
+ unsigned char ch;
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) {
/* Disable the TX Empty interrupt */
writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR);
return;
}
numbytes = port->fifosize;
- while (numbytes && !uart_circ_empty(xmit) &&
- !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL)) {
-
- writel(xmit->buf[xmit->tail], port->membase + CDNS_UART_FIFO);
- uart_xmit_advance(port, 1);
+ while (numbytes &&
+ !(readl(port->membase + CDNS_UART_SR) & CDNS_UART_SR_TXFULL) &&
+ uart_fifo_get(port, &ch)) {
+ writel(ch, port->membase + CDNS_UART_FIFO);
numbytes--;
}
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(port);
/* Enable the TX Empty interrupt */
writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER);
if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED &&
- (uart_circ_empty(xmit) || uart_tx_stopped(port))) {
- cdns_uart->tx_timer.function = &cdns_rs485_rx_callback;
+ (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))) {
+ hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_rx_callback);
hrtimer_start(&cdns_uart->tx_timer,
ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL);
}
@@ -492,7 +495,7 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id)
!(readl(port->membase + CDNS_UART_CR) & CDNS_UART_CR_RX_DIS))
cdns_uart_handle_rx(dev_id, isrstatus);
- uart_port_unlock(port);
+ uart_unlock_and_check_sysrq(port);
return IRQ_HANDLED;
}
@@ -723,7 +726,7 @@ static void cdns_uart_start_tx(struct uart_port *port)
status |= CDNS_UART_CR_TX_EN;
writel(status, port->membase + CDNS_UART_CR);
- if (uart_circ_empty(&port->state->xmit))
+ if (kfifo_is_empty(&port->state->port.xmit_fifo))
return;
/* Clear the TX Empty interrupt */
@@ -731,7 +734,7 @@ static void cdns_uart_start_tx(struct uart_port *port)
if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) {
if (!cdns_uart->rs485_tx_started) {
- cdns_uart->tx_timer.function = &cdns_rs485_tx_callback;
+ hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_tx_callback);
cdns_rs485_tx_setup(cdns_uart);
return hrtimer_start(&cdns_uart->tx_timer,
ms_to_ktime(port->rs485.delay_rts_before_send),
@@ -948,6 +951,10 @@ static int cdns_uart_startup(struct uart_port *port)
is_brk_support = cdns_uart->quirks & CDNS_UART_RXBS_SUPPORT;
+ ret = reset_control_deassert(cdns_uart->rstc);
+ if (ret)
+ return ret;
+
uart_port_lock_irqsave(port, &flags);
/* Disable the TX and RX */
@@ -1373,9 +1380,7 @@ static void cdns_uart_console_write(struct console *co, const char *s,
unsigned int imr, ctrl;
int locked = 1;
- if (port->sysrq)
- locked = 0;
- else if (oops_in_progress)
+ if (oops_in_progress)
locked = uart_port_trylock_irqsave(port, &flags);
else
uart_port_lock_irqsave(port, &flags);
@@ -1621,8 +1626,8 @@ static int cdns_rs485_config(struct uart_port *port, struct ktermios *termios,
writel(val, port->membase + CDNS_UART_MODEMCR);
/* Timer setup */
- hrtimer_init(&cdns_uart->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- cdns_uart->tx_timer.function = &cdns_rs485_tx_callback;
+ hrtimer_setup(&cdns_uart->tx_timer, &cdns_rs485_tx_callback, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
/* Disable transmitter and make Rx setup*/
cdns_uart_stop_tx(port);
@@ -1721,6 +1726,13 @@ static int cdns_uart_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n");
}
+ cdns_uart_data->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
+ if (IS_ERR(cdns_uart_data->rstc)) {
+ rc = PTR_ERR(cdns_uart_data->rstc);
+ dev_err_probe(&pdev->dev, rc, "Cannot get UART reset\n");
+ goto err_out_unregister_driver;
+ }
+
rc = clk_prepare_enable(cdns_uart_data->pclk);
if (rc) {
dev_err(&pdev->dev, "Unable to enable pclk clock.\n");
@@ -1881,6 +1893,7 @@ static void cdns_uart_remove(struct platform_device *pdev)
if (console_port == port)
console_port = NULL;
#endif
+ reset_control_assert(cdns_uart_data->rstc);
if (!--instances)
uart_unregister_driver(cdns_uart_data->cdns_uart_driver);
@@ -1888,7 +1901,7 @@ static void cdns_uart_remove(struct platform_device *pdev)
static struct platform_driver cdns_uart_platform_driver = {
.probe = cdns_uart_probe,
- .remove_new = cdns_uart_remove,
+ .remove = cdns_uart_remove,
.driver = {
.name = CDNS_UART_NAME,
.of_match_table = cdns_uart_of_match,
diff --git a/drivers/tty/serial/zs.c b/drivers/tty/serial/zs.c
index 65ca4da6e368..79ea7108a0f3 100644
--- a/drivers/tty/serial/zs.c
+++ b/drivers/tty/serial/zs.c
@@ -606,7 +606,8 @@ static void zs_receive_chars(struct zs_port *zport)
static void zs_raw_transmit_chars(struct zs_port *zport)
{
- struct circ_buf *xmit = &zport->port.state->xmit;
+ struct tty_port *tport = &zport->port.state->port;
+ unsigned char ch;
/* XON/XOFF chars. */
if (zport->port.x_char) {
@@ -617,20 +618,20 @@ static void zs_raw_transmit_chars(struct zs_port *zport)
}
/* If nothing to do or stopped or hardware stopped. */
- if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) {
+ if (uart_tx_stopped(&zport->port) ||
+ !uart_fifo_get(&zport->port, &ch)) {
zs_raw_stop_tx(zport);
return;
}
/* Send char. */
- write_zsdata(zport, xmit->buf[xmit->tail]);
- uart_xmit_advance(&zport->port, 1);
+ write_zsdata(zport, ch);
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
uart_write_wakeup(&zport->port);
/* Are we are done? */
- if (uart_circ_empty(xmit))
+ if (kfifo_is_empty(&tport->xmit_fifo))
zs_raw_stop_tx(zport);
}
diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c
index 8112d9d5a0d8..4c703f42680d 100644
--- a/drivers/tty/synclink_gt.c
+++ b/drivers/tty/synclink_gt.c
@@ -89,6 +89,7 @@
*/
static const char driver_name[] = "SyncLink GT";
static const char tty_dev_prefix[] = "ttySLG";
+MODULE_DESCRIPTION("Device driver for Microgate SyncLink GT serial adapters");
MODULE_LICENSE("GPL");
#define MAX_DEVICES 32
@@ -2219,7 +2220,7 @@ static void isr_txeom(struct slgt_info *info, unsigned short status)
}
info->tx_active = false;
- del_timer(&info->tx_timer);
+ timer_delete(&info->tx_timer);
if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) {
info->signals &= ~SerialSignal_RTS;
@@ -2374,8 +2375,8 @@ static void shutdown(struct slgt_info *info)
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
- del_timer_sync(&info->tx_timer);
- del_timer_sync(&info->rx_timer);
+ timer_delete_sync(&info->tx_timer);
+ timer_delete_sync(&info->rx_timer);
kfree(info->tx_buf);
info->tx_buf = NULL;
@@ -3954,7 +3955,7 @@ static void tx_stop(struct slgt_info *info)
{
unsigned short val;
- del_timer(&info->tx_timer);
+ timer_delete(&info->tx_timer);
tdma_reset(info);
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 02217e3c916b..6853c4660e7c 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -450,6 +450,17 @@ static const struct sysrq_key_op sysrq_unrt_op = {
.enable_mask = SYSRQ_ENABLE_RTNICE,
};
+static void sysrq_handle_replay_logs(u8 key)
+{
+ console_try_replay_all();
+}
+static struct sysrq_key_op sysrq_replay_logs_op = {
+ .handler = sysrq_handle_replay_logs,
+ .help_msg = "replay-kernel-logs(R)",
+ .action_msg = "Replay kernel logs on consoles",
+ .enable_mask = SYSRQ_ENABLE_DUMP,
+};
+
/* Key Operations table and lock */
static DEFINE_SPINLOCK(sysrq_key_table_lock);
@@ -519,7 +530,8 @@ static const struct sysrq_key_op *sysrq_key_table[62] = {
NULL, /* O */
NULL, /* P */
NULL, /* Q */
- NULL, /* R */
+ &sysrq_replay_logs_op, /* R */
+ /* S: May be registered by sched_ext for resetting */
NULL, /* S */
NULL, /* T */
NULL, /* U */
@@ -571,7 +583,6 @@ static void __sysrq_put_key_op(u8 key, const struct sysrq_key_op *op_p)
void __handle_sysrq(u8 key, bool check_mask)
{
const struct sysrq_key_op *op_p;
- int orig_log_level;
int orig_suppress_printk;
int i;
@@ -581,13 +592,12 @@ void __handle_sysrq(u8 key, bool check_mask)
rcu_sysrq_start();
rcu_read_lock();
/*
- * Raise the apparent loglevel to maximum so that the sysrq header
- * is shown to provide the user with positive feedback. We do not
- * simply emit this at KERN_EMERG as that would change message
- * routing in the consumers of /proc/kmsg.
+ * Enter in the force_console context so that sysrq header is shown to
+ * provide the user with positive feedback. We do not simply emit this
+ * at KERN_EMERG as that would change message routing in the consumers
+ * of /proc/kmsg.
*/
- orig_log_level = console_loglevel;
- console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
+ printk_force_console_enter();
op_p = __sysrq_get_key_op(key);
if (op_p) {
@@ -597,11 +607,11 @@ void __handle_sysrq(u8 key, bool check_mask)
*/
if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
pr_info("%s\n", op_p->action_msg);
- console_loglevel = orig_log_level;
+ printk_force_console_exit();
op_p->handler(key);
} else {
pr_info("This sysrq operation is disabled.\n");
- console_loglevel = orig_log_level;
+ printk_force_console_exit();
}
} else {
pr_info("HELP : ");
@@ -619,7 +629,7 @@ void __handle_sysrq(u8 key, bool check_mask)
}
}
pr_cont("\n");
- console_loglevel = orig_log_level;
+ printk_force_console_exit();
}
rcu_read_unlock();
rcu_sysrq_end();
@@ -733,7 +743,7 @@ static void sysrq_detect_reset_sequence(struct sysrq_state *state,
*/
if (value && state->reset_seq_cnt) {
state->reset_canceled = true;
- del_timer(&state->keyreset_timer);
+ timer_delete(&state->keyreset_timer);
}
} else if (value == 0) {
/*
@@ -741,7 +751,7 @@ static void sysrq_detect_reset_sequence(struct sysrq_state *state,
* to be pressed and held for the reset timeout
* to hold.
*/
- del_timer(&state->keyreset_timer);
+ timer_delete(&state->keyreset_timer);
if (--state->reset_seq_cnt == 0)
state->reset_canceled = false;
@@ -759,8 +769,6 @@ static void sysrq_of_get_keyreset_config(void)
{
u32 key;
struct device_node *np;
- struct property *prop;
- const __be32 *p;
np = of_find_node_by_path("/chosen/linux,sysrq-reset-seq");
if (!np) {
@@ -771,7 +779,7 @@ static void sysrq_of_get_keyreset_config(void)
/* Reset in case a __weak definition was present */
sysrq_reset_seq_len = 0;
- of_property_for_each_u32(np, "keyset", prop, p, key) {
+ of_property_for_each_u32(np, "keyset", key) {
if (key == KEY_RESERVED || key > KEY_MAX ||
sysrq_reset_seq_len == SYSRQ_KEY_RESET_MAX)
break;
diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c
index 1d81eeefb068..75542333c54a 100644
--- a/drivers/tty/tty_audit.c
+++ b/drivers/tty/tty_audit.c
@@ -12,12 +12,14 @@
#include <linux/tty.h>
#include "tty.h"
+#define TTY_AUDIT_BUF_SIZE 4096
+
struct tty_audit_buf {
struct mutex mutex; /* Protects all data below */
dev_t dev; /* The TTY which the data is from */
bool icanon;
size_t valid;
- u8 *data; /* Allocated size N_TTY_BUF_SIZE */
+ u8 *data; /* Allocated size TTY_AUDIT_BUF_SIZE */
};
static struct tty_audit_buf *tty_audit_buf_ref(void)
@@ -37,7 +39,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(void)
if (!buf)
goto err;
- buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
+ buf->data = kmalloc(TTY_AUDIT_BUF_SIZE, GFP_KERNEL);
if (!buf->data)
goto err_buf;
@@ -235,14 +237,14 @@ void tty_audit_add_data(const struct tty_struct *tty, const void *data,
do {
size_t run;
- run = N_TTY_BUF_SIZE - buf->valid;
+ run = TTY_AUDIT_BUF_SIZE - buf->valid;
if (run > size)
run = size;
memcpy(buf->data + buf->valid, data, run);
buf->valid += run;
data += run;
size -= run;
- if (buf->valid == N_TTY_BUF_SIZE)
+ if (buf->valid == TTY_AUDIT_BUF_SIZE)
tty_audit_buf_push(buf);
} while (size != 0);
mutex_unlock(&buf->mutex);
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 407b0d87b7c1..ca9b7d7bad2b 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -350,22 +350,19 @@ int tty_dev_name_to_number(const char *name, dev_t *number)
return ret;
prefix_length = str - name;
- mutex_lock(&tty_mutex);
+
+ guard(mutex)(&tty_mutex);
list_for_each_entry(p, &tty_drivers, tty_drivers)
if (prefix_length == strlen(p->name) && strncmp(name,
p->name, prefix_length) == 0) {
if (index < p->num) {
*number = MKDEV(p->major, p->minor_start + index);
- goto out;
+ return 0;
}
}
- /* if here then driver wasn't found */
- ret = -ENODEV;
-out:
- mutex_unlock(&tty_mutex);
- return ret;
+ return -ENODEV;
}
EXPORT_SYMBOL_GPL(tty_dev_name_to_number);
@@ -462,7 +459,6 @@ static void tty_show_fdinfo(struct seq_file *m, struct file *file)
}
static const struct file_operations tty_fops = {
- .llseek = no_llseek,
.read_iter = tty_read,
.write_iter = tty_write,
.splice_read = copy_splice_read,
@@ -477,7 +473,6 @@ static const struct file_operations tty_fops = {
};
static const struct file_operations console_fops = {
- .llseek = no_llseek,
.read_iter = tty_read,
.write_iter = redirected_tty_write,
.splice_read = copy_splice_read,
@@ -491,7 +486,6 @@ static const struct file_operations console_fops = {
};
static const struct file_operations hung_up_tty_fops = {
- .llseek = no_llseek,
.read_iter = hung_up_tty_read,
.write_iter = hung_up_tty_write,
.poll = hung_up_tty_poll,
@@ -2225,6 +2219,12 @@ static int __tty_fasync(int fd, struct file *filp, int on)
if (tty_paranoia_check(tty, file_inode(filp), "tty_fasync"))
goto out;
+ if (on) {
+ retval = file_f_owner_allocate(filp);
+ if (retval)
+ goto out;
+ }
+
retval = fasync_helper(fd, filp, on, &tty->fasync);
if (retval <= 0)
goto out;
@@ -2622,14 +2622,13 @@ static int tty_tiocgicount(struct tty_struct *tty, void __user *arg)
static int tty_set_serial(struct tty_struct *tty, struct serial_struct *ss)
{
- char comm[TASK_COMM_LEN];
int flags;
flags = ss->flags & ASYNC_DEPRECATED;
if (flags)
pr_warn_ratelimited("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n",
- __func__, get_task_comm(comm, current), flags);
+ __func__, current->comm, flags);
if (!tty->ops->set_serial)
return -ENOTTY;
@@ -3330,10 +3329,12 @@ EXPORT_SYMBOL(tty_unregister_device);
* __tty_alloc_driver - allocate tty driver
* @lines: count of lines this driver can handle at most
* @owner: module which is responsible for this driver
- * @flags: some of %TTY_DRIVER_ flags, will be set in driver->flags
+ * @flags: some of enum tty_driver_flag, will be set in driver->flags
+ *
+ * This should not be called directly, tty_alloc_driver() should be used
+ * instead.
*
- * This should not be called directly, some of the provided macros should be
- * used instead. Use IS_ERR() and friends on @retval.
+ * Returns: struct tty_driver or a PTR-encoded error (use IS_ERR() and friends).
*/
struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
unsigned long flags)
@@ -3567,7 +3568,7 @@ static ssize_t show_cons_active(struct device *dev,
for_each_console(c) {
if (!c->device)
continue;
- if (!c->write)
+ if (!(c->flags & CON_NBCON) && !c->write)
continue;
if ((c->flags & CON_ENABLED) == 0)
continue;
@@ -3618,7 +3619,7 @@ void console_sysfs_notify(void)
sysfs_notify(&consdev->kobj, NULL, "active");
}
-static struct ctl_table tty_table[] = {
+static const struct ctl_table tty_table[] = {
{
.procname = "legacy_tiocsti",
.data = &tty_legacy_tiocsti,
@@ -3631,7 +3632,7 @@ static struct ctl_table tty_table[] = {
.data = &tty_ldisc_autoload,
.maxlen = sizeof(tty_ldisc_autoload),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_dointvec_minmax,
.extra1 = SYSCTL_ZERO,
.extra2 = SYSCTL_ONE,
},
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 3f68e213df1f..d80e9d4c974b 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -545,6 +545,12 @@ int tty_set_ldisc(struct tty_struct *tty, int disc)
goto out;
}
+ if (tty->ops->ldisc_ok) {
+ retval = tty->ops->ldisc_ok(tty, disc);
+ if (retval)
+ goto out;
+ }
+
old_ldisc = tty->ldisc;
/* Shutdown the old discipline. */
diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c
index 3be428c16260..4e18031a5ca3 100644
--- a/drivers/tty/tty_ldsem.c
+++ b/drivers/tty/tty_ldsem.c
@@ -367,23 +367,6 @@ int __sched ldsem_down_write(struct ld_semaphore *sem, long timeout)
}
/*
- * trylock for writing -- returns 1 if successful, 0 if contention
- */
-int ldsem_down_write_trylock(struct ld_semaphore *sem)
-{
- long count = atomic_long_read(&sem->count);
-
- while ((count & LDSEM_ACTIVE_MASK) == 0) {
- if (atomic_long_try_cmpxchg(&sem->count, &count, count + LDSEM_WRITE_BIAS)) {
- rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_);
- lock_acquired(&sem->dep_map, _RET_IP_);
- return 1;
- }
- }
- return 0;
-}
-
-/*
* release a read lock
*/
void ldsem_up_read(struct ld_semaphore *sem)
diff --git a/drivers/tty/ttynull.c b/drivers/tty/ttynull.c
index e4c4273993bc..6b2f7208b564 100644
--- a/drivers/tty/ttynull.c
+++ b/drivers/tty/ttynull.c
@@ -106,4 +106,5 @@ static void __exit ttynull_exit(void)
module_init(ttynull_init);
module_exit(ttynull_exit);
+MODULE_DESCRIPTION("NULL TTY driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/vcc.c b/drivers/tty/vcc.c
index 5b625f20233b..7ac3048377d5 100644
--- a/drivers/tty/vcc.c
+++ b/drivers/tty/vcc.c
@@ -683,8 +683,8 @@ static void vcc_remove(struct vio_dev *vdev)
{
struct vcc_port *port = dev_get_drvdata(&vdev->dev);
- del_timer_sync(&port->rx_timer);
- del_timer_sync(&port->tx_timer);
+ timer_delete_sync(&port->rx_timer);
+ timer_delete_sync(&port->tx_timer);
/* If there's a process with the device open, do a synchronous
* hangup of the TTY. This *may* cause the process to call close
@@ -700,7 +700,7 @@ static void vcc_remove(struct vio_dev *vdev)
tty_unregister_device(vcc_tty_driver, port->index);
- del_timer_sync(&port->vio.timer);
+ timer_delete_sync(&port->vio.timer);
vio_ldc_free(&port->vio);
sysfs_remove_group(&vdev->dev.kobj, &vcc_attribute_group);
dev_set_drvdata(&vdev->dev, NULL);
diff --git a/drivers/tty/vt/conmakehash.c b/drivers/tty/vt/conmakehash.c
index cddd789fe46e..a931fcde7ad9 100644
--- a/drivers/tty/vt/conmakehash.c
+++ b/drivers/tty/vt/conmakehash.c
@@ -76,7 +76,7 @@ static void addpair(int fp, int un)
int main(int argc, char *argv[])
{
FILE *ctbl;
- char *tblname;
+ const char *tblname;
char buffer[65536];
int fontlen;
int i, nuni, nent;
@@ -244,16 +244,13 @@ int main(int argc, char *argv[])
printf("\
/*\n\
- * Do not edit this file; it was automatically generated by\n\
- *\n\
- * conmakehash %s > [this file]\n\
- *\n\
+ * Automatically generated file; Do not edit.\n\
*/\n\
\n\
#include <linux/types.h>\n\
\n\
u8 dfont_unicount[%d] = \n\
-{\n\t", argv[1], fontlen);
+{\n\t", fontlen);
for ( i = 0 ; i < fontlen ; i++ )
{
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c
index a2116e135a82..ae92e6a50a65 100644
--- a/drivers/tty/vt/keyboard.c
+++ b/drivers/tty/vt/keyboard.c
@@ -275,7 +275,7 @@ static DEFINE_TIMER(kd_mksound_timer, kd_nosound);
void kd_mksound(unsigned int hz, unsigned int ticks)
{
- del_timer_sync(&kd_mksound_timer);
+ timer_delete_sync(&kd_mksound_timer);
input_handler_for_each_handle(&kbd_handler, &hz, kd_sound_helper);
@@ -1033,9 +1033,7 @@ static int kbd_led_trigger_activate(struct led_classdev *cdev)
tasklet_disable(&keyboard_tasklet);
if (ledstate != -1U)
- led_trigger_event(&trigger->trigger,
- ledstate & trigger->mask ?
- LED_FULL : LED_OFF);
+ led_set_brightness(cdev, ledstate & trigger->mask ? LED_FULL : LED_OFF);
tasklet_enable(&keyboard_tasklet);
return 0;
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c
index 564341f1a74f..791e2f1f7c0b 100644
--- a/drivers/tty/vt/selection.c
+++ b/drivers/tty/vt/selection.c
@@ -192,6 +192,19 @@ int set_selection_user(const struct tiocl_selection __user *sel,
if (copy_from_user(&v, sel, sizeof(*sel)))
return -EFAULT;
+ /*
+ * TIOCL_SELCLEAR and TIOCL_SELPOINTER are OK to use without
+ * CAP_SYS_ADMIN as they do not modify the selection.
+ */
+ switch (v.sel_mode) {
+ case TIOCL_SELCLEAR:
+ case TIOCL_SELPOINTER:
+ break;
+ default:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ }
+
return set_selection_kernel(&v, tty);
}
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c
index 67e2cb7c96ee..79b33d998d43 100644
--- a/drivers/tty/vt/vc_screen.c
+++ b/drivers/tty/vt/vc_screen.c
@@ -48,10 +48,10 @@
#include <linux/uaccess.h>
#include <asm/byteorder.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define HEADER_SIZE 4u
-#define CON_BUF_SIZE (CONFIG_BASE_SMALL ? 256 : PAGE_SIZE)
+#define CON_BUF_SIZE (IS_ENABLED(CONFIG_BASE_SMALL) ? 256 : PAGE_SIZE)
/*
* Our minor space:
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 9b5b98dfc8b4..f5642b3038e4 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -3345,8 +3345,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg)
switch (type) {
case TIOCL_SETSEL:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
return set_selection_user(param, tty);
case TIOCL_PASTESEL:
if (!capable(CAP_SYS_ADMIN))
@@ -3576,6 +3574,15 @@ static void con_cleanup(struct tty_struct *tty)
tty_port_put(&vc->port);
}
+/*
+ * We can't deal with anything but the N_TTY ldisc,
+ * because we can sleep in our write() routine.
+ */
+static int con_ldisc_ok(struct tty_struct *tty, int ldisc)
+{
+ return ldisc == N_TTY ? 0 : -EINVAL;
+}
+
static int default_color = 7; /* white */
static int default_italic_color = 2; // green (ASCII)
static int default_underline_color = 3; // cyan (ASCII)
@@ -3695,6 +3702,7 @@ static const struct tty_operations con_ops = {
.resize = vt_resize,
.shutdown = con_shutdown,
.cleanup = con_cleanup,
+ .ldisc_ok = con_ldisc_ok,
};
static struct cdev vc0_cdev;
@@ -4493,7 +4501,7 @@ void do_blank_screen(int entering_gfx)
}
hide_cursor(vc);
- del_timer_sync(&console_timer);
+ timer_delete_sync(&console_timer);
blank_timer_expired = 0;
save_screen(vc);
@@ -4598,7 +4606,7 @@ void poke_blanked_console(void)
/* This isn't perfectly race free, but a race here would be mostly harmless,
* at worst, we'll do a spurious blank and it's unlikely
*/
- del_timer(&console_timer);
+ timer_delete(&console_timer);
blank_timer_expired = 0;
if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
@@ -4716,7 +4724,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op)
return -EINVAL;
if (op->data) {
- font.data = kvmalloc(max_font_size, GFP_KERNEL);
+ font.data = kvzalloc(max_font_size, GFP_KERNEL);
if (!font.data)
return -ENOMEM;
} else