diff options
Diffstat (limited to 'kernel/drivers/tty')
115 files changed, 10137 insertions, 6931 deletions
diff --git a/kernel/drivers/tty/amiserial.c b/kernel/drivers/tty/amiserial.c index b2d760055..e53d9a512 100644 --- a/kernel/drivers/tty/amiserial.c +++ b/kernel/drivers/tty/amiserial.c @@ -966,9 +966,7 @@ static void rs_throttle(struct tty_struct * tty) struct serial_state *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", tty_name(tty, buf), + printk("throttle %s: %d....\n", tty_name(tty), tty->ldisc.chars_in_buffer(tty)); #endif @@ -991,9 +989,7 @@ static void rs_unthrottle(struct tty_struct * tty) struct serial_state *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", tty_name(tty, buf), + printk("unthrottle %s: %d....\n", tty_name(tty), tty->ldisc.chars_in_buffer(tty)); #endif @@ -1786,7 +1782,8 @@ static int __exit amiga_serial_remove(struct platform_device *pdev) struct serial_state *state = platform_get_drvdata(pdev); /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ - if ((error = tty_unregister_driver(serial_driver))) + error = tty_unregister_driver(serial_driver); + if (error) printk("SERIAL: failed to unregister serial driver (%d)\n", error); put_tty_driver(serial_driver); diff --git a/kernel/drivers/tty/cyclades.c b/kernel/drivers/tty/cyclades.c index fd66f5739..d4a133167 100644 --- a/kernel/drivers/tty/cyclades.c +++ b/kernel/drivers/tty/cyclades.c @@ -1577,15 +1577,6 @@ static int cy_open(struct tty_struct *tty, struct file *filp) #endif /* - * If the port is the middle of closing, bail out now - */ - if (info->port.flags & ASYNC_CLOSING) { - wait_event_interruptible_tty(tty, info->port.close_wait, - !(info->port.flags & ASYNC_CLOSING)); - return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; - } - - /* * Start up serial port */ retval = cy_startup(info, tty); @@ -2861,9 +2852,7 @@ static void cy_throttle(struct tty_struct *tty) unsigned long flags; #ifdef CY_DEBUG_THROTTLE - char buf[64]; - - printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf), + printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty), tty->ldisc.chars_in_buffer(tty), info->line); #endif @@ -2902,10 +2891,8 @@ static void cy_unthrottle(struct tty_struct *tty) unsigned long flags; #ifdef CY_DEBUG_THROTTLE - char buf[64]; - printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n", - tty_name(tty, buf), tty_chars_in_buffer(tty), info->line); + tty_name(tty), tty_chars_in_buffer(tty), info->line); #endif if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) diff --git a/kernel/drivers/tty/goldfish.c b/kernel/drivers/tty/goldfish.c index 0655fecf8..0f82c0b14 100644 --- a/kernel/drivers/tty/goldfish.c +++ b/kernel/drivers/tty/goldfish.c @@ -59,7 +59,7 @@ static void goldfish_tty_do_write(int line, const char *buf, unsigned count) struct goldfish_tty *qtty = &goldfish_ttys[line]; void __iomem *base = qtty->base; spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write64((u64)buf, base + GOLDFISH_TTY_DATA_PTR, + gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR, base + GOLDFISH_TTY_DATA_PTR_HIGH); writel(count, base + GOLDFISH_TTY_DATA_LEN); writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD); @@ -81,7 +81,7 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) count = tty_prepare_flip_string(&qtty->port, &buf, count); spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write64((u64)buf, base + GOLDFISH_TTY_DATA_PTR, + gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR, base + GOLDFISH_TTY_DATA_PTR_HIGH); writel(count, base + GOLDFISH_TTY_DATA_LEN); writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD); diff --git a/kernel/drivers/tty/hvc/Kconfig b/kernel/drivers/tty/hvc/Kconfig index 8902f9b4d..574da15fe 100644 --- a/kernel/drivers/tty/hvc/Kconfig +++ b/kernel/drivers/tty/hvc/Kconfig @@ -42,13 +42,6 @@ config HVC_RTAS help IBM Console device driver which makes use of RTAS -config HVC_BEAT - bool "Toshiba's Beat Hypervisor Console support" - depends on PPC_CELLEB - select HVC_DRIVER - help - Toshiba's Cell Reference Set Beat Console device driver - config HVC_IUCV bool "z/VM IUCV Hypervisor console support (VM only)" depends on S390 @@ -88,7 +81,7 @@ config HVC_UDBG config HVC_DCC bool "ARM JTAG DCC console" - depends on ARM + depends on ARM || ARM64 select HVC_DRIVER help This console uses the JTAG DCC on ARM to create a console under the HVC diff --git a/kernel/drivers/tty/hvc/Makefile b/kernel/drivers/tty/hvc/Makefile index 4ca3723b0..6a2702be7 100644 --- a/kernel/drivers/tty/hvc/Makefile +++ b/kernel/drivers/tty/hvc/Makefile @@ -4,7 +4,6 @@ obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_TILE) += hvc_tile.o obj-$(CONFIG_HVC_DCC) += hvc_dcc.o -obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o obj-$(CONFIG_HVC_IRQ) += hvc_irq.o obj-$(CONFIG_HVC_XEN) += hvc_xen.o diff --git a/kernel/drivers/tty/hvc/hvc_beat.c b/kernel/drivers/tty/hvc/hvc_beat.c deleted file mode 100644 index 1560d2354..000000000 --- a/kernel/drivers/tty/hvc/hvc_beat.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Beat hypervisor console driver - * - * (C) Copyright 2006 TOSHIBA CORPORATION - * - * This code is based on drivers/char/hvc_rtas.c: - * (C) Copyright IBM Corporation 2001-2005 - * (C) Copyright Red Hat, Inc. 2005 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/err.h> -#include <linux/string.h> -#include <linux/console.h> -#include <asm/prom.h> -#include <asm/hvconsole.h> -#include <asm/firmware.h> - -#include "hvc_console.h" - -extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *); -extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t); - -struct hvc_struct *hvc_beat_dev = NULL; - -/* bug: only one queue is available regardless of vtermno */ -static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt) -{ - static unsigned char q[sizeof(unsigned long) * 2] - __attribute__((aligned(sizeof(unsigned long)))); - static int qlen = 0; - u64 got; - -again: - if (qlen) { - if (qlen > cnt) { - memcpy(buf, q, cnt); - qlen -= cnt; - memmove(q + cnt, q, qlen); - return cnt; - } else { /* qlen <= cnt */ - int r; - - memcpy(buf, q, qlen); - r = qlen; - qlen = 0; - return r; - } - } - if (beat_get_term_char(vtermno, &got, - ((u64 *)q), ((u64 *)q) + 1) == 0) { - qlen = got; - goto again; - } - return 0; -} - -static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt) -{ - unsigned long kb[2]; - int rest, nlen; - - for (rest = cnt; rest > 0; rest -= nlen) { - nlen = (rest > 16) ? 16 : rest; - memcpy(kb, buf, nlen); - beat_put_term_char(vtermno, nlen, kb[0], kb[1]); - buf += nlen; - } - return cnt; -} - -static const struct hv_ops hvc_beat_get_put_ops = { - .get_chars = hvc_beat_get_chars, - .put_chars = hvc_beat_put_chars, -}; - -static int hvc_beat_useit = 1; - -static int hvc_beat_config(char *p) -{ - hvc_beat_useit = simple_strtoul(p, NULL, 0); - return 0; -} - -static int __init hvc_beat_console_init(void) -{ - if (hvc_beat_useit && of_machine_is_compatible("Beat")) { - hvc_instantiate(0, 0, &hvc_beat_get_put_ops); - } - return 0; -} - -/* temp */ -static int __init hvc_beat_init(void) -{ - struct hvc_struct *hp; - - if (!firmware_has_feature(FW_FEATURE_BEAT)) - return -ENODEV; - - hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16); - if (IS_ERR(hp)) - return PTR_ERR(hp); - hvc_beat_dev = hp; - return 0; -} - -static void __exit hvc_beat_exit(void) -{ - if (hvc_beat_dev) - hvc_remove(hvc_beat_dev); -} - -module_init(hvc_beat_init); -module_exit(hvc_beat_exit); - -__setup("hvc_beat=", hvc_beat_config); - -console_initcall(hvc_beat_console_init); diff --git a/kernel/drivers/tty/hvc/hvc_console.c b/kernel/drivers/tty/hvc/hvc_console.c index 4fcec1d79..e46d62899 100644 --- a/kernel/drivers/tty/hvc/hvc_console.c +++ b/kernel/drivers/tty/hvc/hvc_console.c @@ -29,7 +29,7 @@ #include <linux/kernel.h> #include <linux/kthread.h> #include <linux/list.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/major.h> #include <linux/atomic.h> #include <linux/sysrq.h> @@ -319,7 +319,8 @@ static int hvc_install(struct tty_driver *driver, struct tty_struct *tty) int rc; /* Auto increments kref reference if found. */ - if (!(hp = hvc_get_by_index(tty->index))) + hp = hvc_get_by_index(tty->index); + if (!hp) return -ENODEV; tty->driver_data = hp; @@ -417,7 +418,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) * there is no buffered data otherwise sleeps on a wait queue * waking periodically to check chars_in_buffer(). */ - tty_wait_until_sent_from_close(tty, HVC_CLOSE_WAIT); + tty_wait_until_sent(tty, HVC_CLOSE_WAIT); } else { if (hp->port.count < 0) printk(KERN_ERR "hvc_close %X: oops, count is %d\n", @@ -1004,19 +1005,3 @@ put_tty: out: return err; } - -/* This isn't particularly necessary due to this being a console driver - * but it is nice to be thorough. - */ -static void __exit hvc_exit(void) -{ - if (hvc_driver) { - kthread_stop(hvc_task); - - tty_unregister_driver(hvc_driver); - /* return tty_struct instances allocated in hvc_init(). */ - put_tty_driver(hvc_driver); - unregister_console(&hvc_console); - } -} -module_exit(hvc_exit); diff --git a/kernel/drivers/tty/hvc/hvc_dcc.c b/kernel/drivers/tty/hvc/hvc_dcc.c index 809920d80..82f240fb9 100644 --- a/kernel/drivers/tty/hvc/hvc_dcc.c +++ b/kernel/drivers/tty/hvc/hvc_dcc.c @@ -70,20 +70,27 @@ static const struct hv_ops hvc_dcc_get_put_ops = { static int __init hvc_dcc_console_init(void) { + int ret; + if (!hvc_dcc_check()) return -ENODEV; - hvc_instantiate(0, 0, &hvc_dcc_get_put_ops); - return 0; + /* Returns -1 if error */ + ret = hvc_instantiate(0, 0, &hvc_dcc_get_put_ops); + + return ret < 0 ? -ENODEV : 0; } console_initcall(hvc_dcc_console_init); static int __init hvc_dcc_init(void) { + struct hvc_struct *p; + if (!hvc_dcc_check()) return -ENODEV; - hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128); - return 0; + p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128); + + return PTR_ERR_OR_ZERO(p); } device_initcall(hvc_dcc_init); diff --git a/kernel/drivers/tty/hvc/hvc_iucv.c b/kernel/drivers/tty/hvc/hvc_iucv.c index f78a87b07..8b70a1627 100644 --- a/kernel/drivers/tty/hvc/hvc_iucv.c +++ b/kernel/drivers/tty/hvc/hvc_iucv.c @@ -88,8 +88,8 @@ struct iucv_tty_buffer { }; /* IUCV callback handler */ -static int hvc_iucv_path_pending(struct iucv_path *, u8[8], u8[16]); -static void hvc_iucv_path_severed(struct iucv_path *, u8[16]); +static int hvc_iucv_path_pending(struct iucv_path *, u8 *, u8 *); +static void hvc_iucv_path_severed(struct iucv_path *, u8 *); static void hvc_iucv_msg_pending(struct iucv_path *, struct iucv_message *); static void hvc_iucv_msg_complete(struct iucv_path *, struct iucv_message *); @@ -782,8 +782,8 @@ static int hvc_iucv_filter_connreq(u8 ipvmid[8]) * * Locking: struct hvc_iucv_private->lock */ -static int hvc_iucv_path_pending(struct iucv_path *path, - u8 ipvmid[8], u8 ipuser[16]) +static int hvc_iucv_path_pending(struct iucv_path *path, u8 *ipvmid, + u8 *ipuser) { struct hvc_iucv_private *priv, *tmp; u8 wildcard[9] = "lnxhvc "; @@ -881,7 +881,7 @@ out_path_handled: * * Locking: struct hvc_iucv_private->lock */ -static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) +static void hvc_iucv_path_severed(struct iucv_path *path, u8 *ipuser) { struct hvc_iucv_private *priv = path->private; @@ -1345,7 +1345,7 @@ static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp) #define param_check_vmidfilter(name, p) __param_check(name, p, void) -static struct kernel_param_ops param_ops_vmidfilter = { +static const struct kernel_param_ops param_ops_vmidfilter = { .set = param_set_vmidfilter, .get = param_get_vmidfilter, }; diff --git a/kernel/drivers/tty/hvc/hvc_opal.c b/kernel/drivers/tty/hvc/hvc_opal.c index 543b234e7..47b54c6ae 100644 --- a/kernel/drivers/tty/hvc/hvc_opal.c +++ b/kernel/drivers/tty/hvc/hvc_opal.c @@ -29,6 +29,7 @@ #include <linux/of.h> #include <linux/of_platform.h> #include <linux/export.h> +#include <linux/interrupt.h> #include <asm/hvconsole.h> #include <asm/prom.h> @@ -61,7 +62,6 @@ static struct hvc_opal_priv *hvc_opal_privs[MAX_NR_HVC_CONSOLES]; /* For early boot console */ static struct hvc_opal_priv hvc_opal_boot_priv; static u32 hvc_opal_boot_termno; -static bool hvc_opal_event_registered; static const struct hv_ops hvc_opal_raw_ops = { .get_chars = opal_get_chars, @@ -162,28 +162,15 @@ static const struct hv_ops hvc_opal_hvsi_ops = { .tiocmset = hvc_opal_hvsi_tiocmset, }; -static int hvc_opal_console_event(struct notifier_block *nb, - unsigned long events, void *change) -{ - if (events & OPAL_EVENT_CONSOLE_INPUT) - hvc_kick(); - return 0; -} - -static struct notifier_block hvc_opal_console_nb = { - .notifier_call = hvc_opal_console_event, -}; - static int hvc_opal_probe(struct platform_device *dev) { const struct hv_ops *ops; struct hvc_struct *hp; struct hvc_opal_priv *pv; hv_protocol_t proto; - unsigned int termno, boot = 0; + unsigned int termno, irq, boot = 0; const __be32 *reg; - if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) { proto = HV_PROTOCOL_RAW; ops = &hvc_opal_raw_ops; @@ -227,18 +214,18 @@ static int hvc_opal_probe(struct platform_device *dev) dev->dev.of_node->full_name, boot ? " (boot console)" : ""); - /* We don't do IRQ ... */ - hp = hvc_alloc(termno, 0, ops, MAX_VIO_PUT_CHARS); + irq = opal_event_request(ilog2(OPAL_EVENT_CONSOLE_INPUT)); + if (!irq) { + pr_err("hvc_opal: Unable to map interrupt for device %s\n", + dev->dev.of_node->full_name); + return irq; + } + + hp = hvc_alloc(termno, irq, ops, MAX_VIO_PUT_CHARS); if (IS_ERR(hp)) return PTR_ERR(hp); dev_set_drvdata(&dev->dev, hp); - /* ... but we use OPAL event to kick the console */ - if (!hvc_opal_event_registered) { - opal_notifier_register(&hvc_opal_console_nb); - hvc_opal_event_registered = true; - } - return 0; } diff --git a/kernel/drivers/tty/hvc/hvc_tile.c b/kernel/drivers/tty/hvc/hvc_tile.c index 3f6cd3102..9da1e842b 100644 --- a/kernel/drivers/tty/hvc/hvc_tile.c +++ b/kernel/drivers/tty/hvc/hvc_tile.c @@ -51,7 +51,8 @@ int tile_console_write(const char *buf, int count) _SIM_CONTROL_OPERATOR_BITS)); return 0; } else { - return hv_console_write((HV_VirtAddr)buf, count); + /* Translate 0 bytes written to EAGAIN for hvc_console_print. */ + return hv_console_write((HV_VirtAddr)buf, count) ?: -EAGAIN; } } diff --git a/kernel/drivers/tty/hvc/hvc_xen.c b/kernel/drivers/tty/hvc/hvc_xen.c index 7a3d146a5..fa816b719 100644 --- a/kernel/drivers/tty/hvc/hvc_xen.c +++ b/kernel/drivers/tty/hvc/hvc_xen.c @@ -200,7 +200,7 @@ static int xen_hvm_console_init(void) { int r; uint64_t v = 0; - unsigned long mfn; + unsigned long gfn; struct xencons_info *info; if (!xen_hvm_domain()) @@ -217,7 +217,7 @@ static int xen_hvm_console_init(void) } /* * If the toolstack (or the hypervisor) hasn't set these values, the - * default value is 0. Even though mfn = 0 and evtchn = 0 are + * default value is 0. Even though gfn = 0 and evtchn = 0 are * theoretically correct values, in practice they never are and they * mean that a legacy toolstack hasn't initialized the pv console correctly. */ @@ -229,8 +229,8 @@ static int xen_hvm_console_init(void) r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); if (r < 0 || v == 0) goto err; - mfn = v; - info->intf = xen_remap(mfn << PAGE_SHIFT, PAGE_SIZE); + gfn = v; + info->intf = xen_remap(gfn << XEN_PAGE_SHIFT, XEN_PAGE_SIZE); if (info->intf == NULL) goto err; info->vtermno = HVC_COOKIE; @@ -265,7 +265,8 @@ static int xen_pv_console_init(void) return 0; } info->evtchn = xen_start_info->console.domU.evtchn; - info->intf = mfn_to_virt(xen_start_info->console.domU.mfn); + /* GFN == MFN for PV guest */ + info->intf = gfn_to_virt(xen_start_info->console.domU.mfn); info->vtermno = HVC_COOKIE; spin_lock(&xencons_lock); @@ -302,7 +303,7 @@ static int xen_initial_domain_console_init(void) static void xen_console_update_evtchn(struct xencons_info *info) { if (xen_hvm_domain()) { - uint64_t v; + uint64_t v = 0; int err; err = hvm_get_parameter(HVM_PARAM_CONSOLE_EVTCHN, &v); @@ -374,7 +375,6 @@ static int xencons_connect_backend(struct xenbus_device *dev, int ret, evtchn, devid, ref, irq; struct xenbus_transaction xbt; grant_ref_t gref_head; - unsigned long mfn; ret = xenbus_alloc_evtchn(dev, &evtchn); if (ret) @@ -389,10 +389,6 @@ static int xencons_connect_backend(struct xenbus_device *dev, irq, &domU_hvc_ops, 256); if (IS_ERR(info->hvc)) return PTR_ERR(info->hvc); - if (xen_pv_domain()) - mfn = virt_to_mfn(info->intf); - else - mfn = __pa(info->intf) >> PAGE_SHIFT; ret = gnttab_alloc_grant_references(1, &gref_head); if (ret < 0) return ret; @@ -401,7 +397,7 @@ static int xencons_connect_backend(struct xenbus_device *dev, if (ref < 0) return ref; gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id, - mfn, 0); + virt_to_gfn(info->intf), 0); again: ret = xenbus_transaction_start(&xbt); @@ -476,7 +472,7 @@ static int xencons_resume(struct xenbus_device *dev) struct xencons_info *info = dev_get_drvdata(&dev->dev); xencons_disconnect_backend(info); - memset(info->intf, 0, PAGE_SIZE); + memset(info->intf, 0, XEN_PAGE_SIZE); return xencons_connect_backend(dev, info); } diff --git a/kernel/drivers/tty/hvc/hvcs.c b/kernel/drivers/tty/hvc/hvcs.c index 81ff7e1bf..5997b1731 100644 --- a/kernel/drivers/tty/hvc/hvcs.c +++ b/kernel/drivers/tty/hvc/hvcs.c @@ -1044,8 +1044,8 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, * It is possible that the vty-server was removed between the time that * the conn was registered and now. */ - if (!(rc = request_irq(irq, &hvcs_handle_interrupt, - 0, "ibmhvcs", hvcsd))) { + rc = request_irq(irq, &hvcs_handle_interrupt, 0, "ibmhvcs", hvcsd); + if (!rc) { /* * It is possible the vty-server was removed after the irq was * requested but before we have time to enable interrupts. @@ -1230,7 +1230,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) irq = hvcsd->vdev->irq; spin_unlock_irqrestore(&hvcsd->lock, flags); - tty_wait_until_sent_from_close(tty, HVCS_CLOSE_WAIT); + tty_wait_until_sent(tty, HVCS_CLOSE_WAIT); /* * This line is important because it tells hvcs_open that this diff --git a/kernel/drivers/tty/hvc/hvsi.c b/kernel/drivers/tty/hvc/hvsi.c index 41901997c..a75146f60 100644 --- a/kernel/drivers/tty/hvc/hvsi.c +++ b/kernel/drivers/tty/hvc/hvsi.c @@ -240,9 +240,9 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, { struct hvsi_control *header = (struct hvsi_control *)packet; - switch (header->verb) { + switch (be16_to_cpu(header->verb)) { case VSV_MODEM_CTL_UPDATE: - if ((header->word & HVSI_TSCD) == 0) { + if ((be32_to_cpu(header->word) & HVSI_TSCD) == 0) { /* CD went away; no more connection */ pr_debug("hvsi%i: CD dropped\n", hp->index); hp->mctrl &= TIOCM_CD; @@ -267,6 +267,7 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet, static void hvsi_recv_response(struct hvsi_struct *hp, uint8_t *packet) { struct hvsi_query_response *resp = (struct hvsi_query_response *)packet; + uint32_t mctrl_word; switch (hp->state) { case HVSI_WAIT_FOR_VER_RESPONSE: @@ -274,9 +275,10 @@ static void hvsi_recv_response(struct hvsi_struct *hp, uint8_t *packet) break; case HVSI_WAIT_FOR_MCTRL_RESPONSE: hp->mctrl = 0; - if (resp->u.mctrl_word & HVSI_TSDTR) + mctrl_word = be32_to_cpu(resp->u.mctrl_word); + if (mctrl_word & HVSI_TSDTR) hp->mctrl |= TIOCM_DTR; - if (resp->u.mctrl_word & HVSI_TSCD) + if (mctrl_word & HVSI_TSCD) hp->mctrl |= TIOCM_CD; __set_state(hp, HVSI_OPEN); break; @@ -295,10 +297,10 @@ static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno) packet.hdr.type = VS_QUERY_RESPONSE_PACKET_HEADER; packet.hdr.len = sizeof(struct hvsi_query_response); - packet.hdr.seqno = atomic_inc_return(&hp->seqno); - packet.verb = VSV_SEND_VERSION_NUMBER; + packet.hdr.seqno = cpu_to_be16(atomic_inc_return(&hp->seqno)); + packet.verb = cpu_to_be16(VSV_SEND_VERSION_NUMBER); packet.u.version = HVSI_VERSION; - packet.query_seqno = query_seqno+1; + packet.query_seqno = cpu_to_be16(query_seqno+1); pr_debug("%s: sending %i bytes\n", __func__, packet.hdr.len); dbg_dump_hex((uint8_t*)&packet, packet.hdr.len); @@ -319,7 +321,7 @@ static void hvsi_recv_query(struct hvsi_struct *hp, uint8_t *packet) switch (hp->state) { case HVSI_WAIT_FOR_VER_QUERY: - hvsi_version_respond(hp, query->hdr.seqno); + hvsi_version_respond(hp, be16_to_cpu(query->hdr.seqno)); __set_state(hp, HVSI_OPEN); break; default: @@ -555,8 +557,8 @@ static int hvsi_query(struct hvsi_struct *hp, uint16_t verb) packet.hdr.type = VS_QUERY_PACKET_HEADER; packet.hdr.len = sizeof(struct hvsi_query); - packet.hdr.seqno = atomic_inc_return(&hp->seqno); - packet.verb = verb; + packet.hdr.seqno = cpu_to_be16(atomic_inc_return(&hp->seqno)); + packet.verb = cpu_to_be16(verb); pr_debug("%s: sending %i bytes\n", __func__, packet.hdr.len); dbg_dump_hex((uint8_t*)&packet, packet.hdr.len); @@ -596,14 +598,14 @@ static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl) struct hvsi_control packet __ALIGNED__; int wrote; - packet.hdr.type = VS_CONTROL_PACKET_HEADER, - packet.hdr.seqno = atomic_inc_return(&hp->seqno); + packet.hdr.type = VS_CONTROL_PACKET_HEADER; + packet.hdr.seqno = cpu_to_be16(atomic_inc_return(&hp->seqno)); packet.hdr.len = sizeof(struct hvsi_control); - packet.verb = VSV_SET_MODEM_CTL; - packet.mask = HVSI_TSDTR; + packet.verb = cpu_to_be16(VSV_SET_MODEM_CTL); + packet.mask = cpu_to_be32(HVSI_TSDTR); if (mctrl & TIOCM_DTR) - packet.word = HVSI_TSDTR; + packet.word = cpu_to_be32(HVSI_TSDTR); pr_debug("%s: sending %i bytes\n", __func__, packet.hdr.len); dbg_dump_hex((uint8_t*)&packet, packet.hdr.len); @@ -680,7 +682,7 @@ static int hvsi_put_chars(struct hvsi_struct *hp, const char *buf, int count) BUG_ON(count > HVSI_MAX_OUTGOING_DATA); packet.hdr.type = VS_DATA_PACKET_HEADER; - packet.hdr.seqno = atomic_inc_return(&hp->seqno); + packet.hdr.seqno = cpu_to_be16(atomic_inc_return(&hp->seqno)); packet.hdr.len = count + sizeof(struct hvsi_header); memcpy(&packet.data, buf, count); @@ -697,9 +699,9 @@ static void hvsi_close_protocol(struct hvsi_struct *hp) struct hvsi_control packet __ALIGNED__; packet.hdr.type = VS_CONTROL_PACKET_HEADER; - packet.hdr.seqno = atomic_inc_return(&hp->seqno); + packet.hdr.seqno = cpu_to_be16(atomic_inc_return(&hp->seqno)); packet.hdr.len = 6; - packet.verb = VSV_CLOSE_PROTOCOL; + packet.verb = cpu_to_be16(VSV_CLOSE_PROTOCOL); pr_debug("%s: sending %i bytes\n", __func__, packet.hdr.len); dbg_dump_hex((uint8_t*)&packet, packet.hdr.len); @@ -1180,7 +1182,7 @@ static int __init hvsi_console_init(void) /* search device tree for vty nodes */ for_each_compatible_node(vty, "serial", "hvterm-protocol") { struct hvsi_struct *hp; - const uint32_t *vtermno, *irq; + const __be32 *vtermno, *irq; vtermno = of_get_property(vty, "reg", NULL); irq = of_get_property(vty, "interrupts", NULL); @@ -1202,11 +1204,11 @@ static int __init hvsi_console_init(void) hp->index = hvsi_count; hp->inbuf_end = hp->inbuf; hp->state = HVSI_CLOSED; - hp->vtermno = *vtermno; - hp->virq = irq_create_mapping(NULL, irq[0]); + hp->vtermno = be32_to_cpup(vtermno); + hp->virq = irq_create_mapping(NULL, be32_to_cpup(irq)); if (hp->virq == 0) { printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", - __func__, irq[0]); + __func__, be32_to_cpup(irq)); tty_port_destroy(&hp->port); continue; } diff --git a/kernel/drivers/tty/metag_da.c b/kernel/drivers/tty/metag_da.c index 377460074..932526228 100644 --- a/kernel/drivers/tty/metag_da.c +++ b/kernel/drivers/tty/metag_da.c @@ -640,25 +640,7 @@ err_destroy_ports: put_tty_driver(channel_driver); return ret; } - -static void dashtty_exit(void) -{ - int nport; - struct dashtty_port *dport; - - del_timer_sync(&put_timer); - kthread_stop(dashtty_thread); - del_timer_sync(&poll_timer); - tty_unregister_driver(channel_driver); - for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) { - dport = &dashtty_ports[nport]; - tty_port_destroy(&dport->port); - } - put_tty_driver(channel_driver); -} - -module_init(dashtty_init); -module_exit(dashtty_exit); +device_initcall(dashtty_init); #ifdef CONFIG_DA_CONSOLE diff --git a/kernel/drivers/tty/mips_ejtag_fdc.c b/kernel/drivers/tty/mips_ejtag_fdc.c index 358323c83..a119176a1 100644 --- a/kernel/drivers/tty/mips_ejtag_fdc.c +++ b/kernel/drivers/tty/mips_ejtag_fdc.c @@ -879,6 +879,11 @@ static const struct tty_operations mips_ejtag_fdc_tty_ops = { .chars_in_buffer = mips_ejtag_fdc_tty_chars_in_buffer, }; +int __weak get_c0_fdc_int(void) +{ + return -1; +} + static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) { int ret, nport; @@ -967,14 +972,12 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) wake_up_process(priv->thread); /* Look for an FDC IRQ */ - priv->irq = -1; - if (get_c0_fdc_int) - priv->irq = get_c0_fdc_int(); + priv->irq = get_c0_fdc_int(); /* Try requesting the IRQ */ if (priv->irq >= 0) { /* - * IRQF_SHARED, IRQF_NO_SUSPEND: The FDC IRQ may be shared with + * IRQF_SHARED, IRQF_COND_SUSPEND: The FDC IRQ may be shared with * other local interrupts such as the timer which sets * IRQF_TIMER (including IRQF_NO_SUSPEND). * @@ -984,7 +987,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) */ ret = devm_request_irq(priv->dev, priv->irq, mips_ejtag_fdc_isr, IRQF_PERCPU | IRQF_SHARED | - IRQF_NO_THREAD | IRQF_NO_SUSPEND, + IRQF_NO_THREAD | IRQF_COND_SUSPEND, priv->fdc_name, priv); if (ret) priv->irq = -1; @@ -1045,38 +1048,6 @@ err_destroy_ports: return ret; } -static int mips_ejtag_fdc_tty_remove(struct mips_cdmm_device *dev) -{ - struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(dev); - struct mips_ejtag_fdc_tty_port *dport; - int nport; - unsigned int cfg; - - if (priv->irq >= 0) { - raw_spin_lock_irq(&priv->lock); - cfg = mips_ejtag_fdc_read(priv, REG_FDCFG); - /* Disable interrupts */ - cfg &= ~(REG_FDCFG_TXINTTHRES | REG_FDCFG_RXINTTHRES); - cfg |= REG_FDCFG_TXINTTHRES_DISABLED; - cfg |= REG_FDCFG_RXINTTHRES_DISABLED; - mips_ejtag_fdc_write(priv, REG_FDCFG, cfg); - raw_spin_unlock_irq(&priv->lock); - } else { - priv->removing = true; - del_timer_sync(&priv->poll_timer); - } - kthread_stop(priv->thread); - if (dev->cpu == 0) - mips_ejtag_fdc_con.tty_drv = NULL; - tty_unregister_driver(priv->driver); - for (nport = 0; nport < NUM_TTY_CHANNELS; nport++) { - dport = &priv->ports[nport]; - tty_port_destroy(&dport->port); - } - put_tty_driver(priv->driver); - return 0; -} - static int mips_ejtag_fdc_tty_cpu_down(struct mips_cdmm_device *dev) { struct mips_ejtag_fdc_tty *priv = mips_cdmm_get_drvdata(dev); @@ -1149,12 +1120,11 @@ static struct mips_cdmm_driver mips_ejtag_fdc_tty_driver = { .name = "mips_ejtag_fdc", }, .probe = mips_ejtag_fdc_tty_probe, - .remove = mips_ejtag_fdc_tty_remove, .cpu_down = mips_ejtag_fdc_tty_cpu_down, .cpu_up = mips_ejtag_fdc_tty_cpu_up, .id_table = mips_ejtag_fdc_tty_ids, }; -module_mips_cdmm_driver(mips_ejtag_fdc_tty_driver); +builtin_mips_cdmm_driver(mips_ejtag_fdc_tty_driver); static int __init mips_ejtag_fdc_init_console(void) { diff --git a/kernel/drivers/tty/n_gsm.c b/kernel/drivers/tty/n_gsm.c index 2c34c3249..c3fe026d3 100644 --- a/kernel/drivers/tty/n_gsm.c +++ b/kernel/drivers/tty/n_gsm.c @@ -161,7 +161,7 @@ struct gsm_dlci { struct net_device *net; /* network interface, if created */ }; -/* DLCI 0, 62/63 are special or reseved see gsmtty_open */ +/* DLCI 0, 62/63 are special or reserved see gsmtty_open */ #define NUM_DLCI 64 @@ -2274,7 +2274,6 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, const unsigned char *dp; char *f; int i; - char buf[64]; char flags = TTY_NORMAL; if (debug & 4) @@ -2296,7 +2295,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, break; default: WARN_ONCE(1, "%s: unknown flag %d\n", - tty_name(tty, buf), flags); + tty_name(tty), flags); break; } } @@ -2713,7 +2712,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, memcpy(skb_put(skb, size), in_buf, size); skb->dev = net; - skb->protocol = __constant_htons(ETH_P_IP); + skb->protocol = htons(ETH_P_IP); /* Ship it off to the kernel */ netif_rx(skb); diff --git a/kernel/drivers/tty/n_r3964.c b/kernel/drivers/tty/n_r3964.c index 8b157d68a..345111467 100644 --- a/kernel/drivers/tty/n_r3964.c +++ b/kernel/drivers/tty/n_r3964.c @@ -276,7 +276,7 @@ static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code) add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length, error_code, NULL); } - wake_up_interruptible(&pInfo->read_wait); + wake_up_interruptible(&pInfo->tty->read_wait); } spin_lock_irqsave(&pInfo->lock, flags); @@ -542,7 +542,7 @@ static void on_receive_block(struct r3964_info *pInfo) pBlock); } } - wake_up_interruptible(&pInfo->read_wait); + wake_up_interruptible(&pInfo->tty->read_wait); pInfo->state = R3964_IDLE; @@ -978,8 +978,8 @@ static int r3964_open(struct tty_struct *tty) } spin_lock_init(&pInfo->lock); + mutex_init(&pInfo->read_lock); pInfo->tty = tty; - init_waitqueue_head(&pInfo->read_wait); pInfo->priority = R3964_MASTER; pInfo->rx_first = pInfo->rx_last = NULL; pInfo->tx_first = pInfo->tx_last = NULL; @@ -1045,7 +1045,6 @@ static void r3964_close(struct tty_struct *tty) } /* Free buffers: */ - wake_up_interruptible(&pInfo->read_wait); kfree(pInfo->rx_buf); TRACE_M("r3964_close - rx_buf kfree %p", pInfo->rx_buf); kfree(pInfo->tx_buf); @@ -1065,7 +1064,16 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, TRACE_L("read()"); - tty_lock(tty); + /* + * Internal serialization of reads. + */ + if (file->f_flags & O_NONBLOCK) { + if (!mutex_trylock(&pInfo->read_lock)) + return -EAGAIN; + } else { + if (mutex_lock_interruptible(&pInfo->read_lock)) + return -ERESTARTSYS; + } pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1077,7 +1085,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, goto unlock; } /* block until there is a message: */ - wait_event_interruptible_tty(tty, pInfo->read_wait, + wait_event_interruptible(tty->read_wait, (pMsg = remove_msg(pInfo, pClient))); } @@ -1107,7 +1115,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, } ret = -EPERM; unlock: - tty_unlock(tty); + mutex_unlock(&pInfo->read_lock); return ret; } @@ -1156,8 +1164,6 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, pHeader->locks = 0; pHeader->owner = NULL; - tty_lock(tty); - pClient = findClient(pInfo, task_pid(current)); if (pClient) { pHeader->owner = pClient; @@ -1175,8 +1181,6 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, add_tx_queue(pInfo, pHeader); trigger_transmit(pInfo); - tty_unlock(tty); - return 0; } @@ -1227,7 +1231,7 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file, pClient = findClient(pInfo, task_pid(current)); if (pClient) { - poll_wait(file, &pInfo->read_wait, wait); + poll_wait(file, &tty->read_wait, wait); spin_lock_irqsave(&pInfo->lock, flags); pMsg = pClient->first_msg; spin_unlock_irqrestore(&pInfo->lock, flags); diff --git a/kernel/drivers/tty/n_tracerouter.c b/kernel/drivers/tty/n_tracerouter.c index 1f063d3aa..ac5716979 100644 --- a/kernel/drivers/tty/n_tracerouter.c +++ b/kernel/drivers/tty/n_tracerouter.c @@ -34,7 +34,7 @@ #include <linux/string.h> #include <linux/mutex.h> #include <linux/slab.h> -#include <asm-generic/bug.h> +#include <linux/bug.h> #include "n_tracesink.h" /* diff --git a/kernel/drivers/tty/n_tracesink.c b/kernel/drivers/tty/n_tracesink.c index ddce58b97..4616870a6 100644 --- a/kernel/drivers/tty/n_tracesink.c +++ b/kernel/drivers/tty/n_tracesink.c @@ -34,7 +34,7 @@ #include <linux/tty_ldisc.h> #include <linux/errno.h> #include <linux/string.h> -#include <asm-generic/bug.h> +#include <linux/bug.h> #include "n_tracesink.h" /* diff --git a/kernel/drivers/tty/n_tty.c b/kernel/drivers/tty/n_tty.c index 16ed0b6c7..cf000b331 100644 --- a/kernel/drivers/tty/n_tty.c +++ b/kernel/drivers/tty/n_tty.c @@ -169,7 +169,7 @@ static inline int tty_copy_to_user(struct tty_struct *tty, { struct n_tty_data *ldata = tty->disc_data; - tty_audit_add_data(tty, to, n, ldata->icanon); + tty_audit_add_data(tty, from, n, ldata->icanon); return copy_to_user(to, from, n); } @@ -201,7 +201,7 @@ static void n_tty_kick_worker(struct tty_struct *tty) */ WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags), "scheduling buffer work for halted ldisc\n"); - queue_work(system_unbound_wq, &tty->port->buf.work); + tty_buffer_restart_work(tty->port); } } @@ -258,16 +258,13 @@ static void n_tty_check_throttle(struct tty_struct *tty) static void n_tty_check_unthrottle(struct tty_struct *tty) { - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->link->ldisc->ops->write_wakeup == n_tty_write_wakeup) { + if (tty->driver->type == TTY_DRIVER_TYPE_PTY) { if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE) return; if (!tty->count) return; n_tty_kick_worker(tty); - n_tty_write_wakeup(tty->link); - if (waitqueue_active(&tty->link->write_wait)) - wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT); + tty_wakeup(tty->link); return; } @@ -343,8 +340,7 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty) spin_lock_irqsave(&tty->ctrl_lock, flags); tty->ctrl_status |= TIOCPKT_FLUSHREAD; spin_unlock_irqrestore(&tty->ctrl_lock, flags); - if (waitqueue_active(&tty->link->read_wait)) - wake_up_interruptible(&tty->link->read_wait); + wake_up_interruptible(&tty->link->read_wait); } } @@ -1180,8 +1176,6 @@ static void n_tty_receive_break(struct tty_struct *tty) put_tty_queue('\0', ldata); } put_tty_queue('\0', ldata); - if (waitqueue_active(&tty->read_wait)) - wake_up_interruptible_poll(&tty->read_wait, POLLIN); } /** @@ -1200,13 +1194,12 @@ static void n_tty_receive_break(struct tty_struct *tty) static void n_tty_receive_overrun(struct tty_struct *tty) { struct n_tty_data *ldata = tty->disc_data; - char buf[64]; ldata->num_overrun++; if (time_after(jiffies, ldata->overrun_time + HZ) || time_after(ldata->overrun_time, jiffies)) { printk(KERN_WARNING "%s: %d input overrun(s)\n", - tty_name(tty, buf), + tty_name(tty), ldata->num_overrun); ldata->overrun_time = jiffies; ldata->num_overrun = 0; @@ -1239,8 +1232,6 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) put_tty_queue('\0', ldata); } else put_tty_queue(c, ldata); - if (waitqueue_active(&tty->read_wait)) - wake_up_interruptible_poll(&tty->read_wait, POLLIN); } static void @@ -1383,8 +1374,7 @@ handle_newline: put_tty_queue(c, ldata); smp_store_release(&ldata->canon_head, ldata->read_head); kill_fasync(&tty->fasync, SIGIO, POLL_IN); - if (waitqueue_active(&tty->read_wait)) - wake_up_interruptible_poll(&tty->read_wait, POLLIN); + wake_up_interruptible_poll(&tty->read_wait, POLLIN); return 0; } } @@ -1481,8 +1471,6 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c) static void n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag) { - char buf[64]; - switch (flag) { case TTY_BREAK: n_tty_receive_break(tty); @@ -1496,7 +1484,7 @@ n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag) break; default: printk(KERN_ERR "%s: unknown flag %d\n", - tty_name(tty, buf), flag); + tty_name(tty), flag); break; } } @@ -1670,8 +1658,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); - if (waitqueue_active(&tty->read_wait)) - wake_up_interruptible_poll(&tty->read_wait, POLLIN); + wake_up_interruptible_poll(&tty->read_wait, POLLIN); } } @@ -1890,10 +1877,8 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) } /* The termios change make the tty ready for I/O */ - if (waitqueue_active(&tty->write_wait)) - wake_up_interruptible(&tty->write_wait); - if (waitqueue_active(&tty->read_wait)) - wake_up_interruptible(&tty->read_wait); + wake_up_interruptible(&tty->write_wait); + wake_up_interruptible(&tty->read_wait); } /** @@ -2066,13 +2051,13 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, size_t eol; size_t tail; int ret, found = 0; - bool eof_push = 0; /* N.B. avoid overrun if nr == 0 */ - n = min(*nr, smp_load_acquire(&ldata->canon_head) - ldata->read_tail); - if (!n) + if (!*nr) return 0; + n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail); + tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1); size = min_t(size_t, tail + n, N_TTY_BUF_SIZE); @@ -2093,12 +2078,11 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, n = eol - tail; if (n > N_TTY_BUF_SIZE) n += N_TTY_BUF_SIZE; - n += found; - c = n; + c = n + found; - if (found && !ldata->push && read_buf(ldata, eol) == __DISABLED_CHAR) { - n--; - eof_push = !n && ldata->read_tail != ldata->line_start; + if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) { + c = min(*nr, c); + n = c; } n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu size:%zu more:%zu\n", @@ -2128,7 +2112,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty, ldata->push = 0; tty_audit_push(tty); } - return eof_push ? -EAGAIN : 0; + return 0; } extern ssize_t redirected_tty_write(struct file *, const char __user *, @@ -2155,23 +2139,10 @@ static int job_control(struct tty_struct *tty, struct file *file) /* NOTE: not yet done after every sleep pending a thorough check of the logic of this change. -- jlc */ /* don't stop on /dev/console */ - if (file->f_op->write == redirected_tty_write || - current->signal->tty != tty) + if (file->f_op->write == redirected_tty_write) return 0; - spin_lock_irq(&tty->ctrl_lock); - if (!tty->pgrp) - printk(KERN_ERR "n_tty_read: no tty->pgrp!\n"); - else if (task_pgrp(current) != tty->pgrp) { - spin_unlock_irq(&tty->ctrl_lock); - if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned()) - return -EIO; - kill_pgrp(task_pgrp(current), SIGTTIN, 1); - set_thread_flag(TIF_SIGPENDING); - return -ERESTARTSYS; - } - spin_unlock_irq(&tty->ctrl_lock); - return 0; + return __tty_check_change(tty, SIGTTIN); } @@ -2298,10 +2269,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, if (ldata->icanon && !L_EXTPROC(tty)) { retval = canon_copy_from_read_buf(tty, &b, &nr); - if (retval == -EAGAIN) { - retval = 0; - continue; - } else if (retval) + if (retval) break; } else { int uncopied; diff --git a/kernel/drivers/tty/nozomi.c b/kernel/drivers/tty/nozomi.c index 74885af8c..80f9de907 100644 --- a/kernel/drivers/tty/nozomi.c +++ b/kernel/drivers/tty/nozomi.c @@ -140,8 +140,8 @@ static int debug; #define R_FCR 0x0000 /* Flow Control Register */ #define R_IER 0x0004 /* Interrupt Enable Register */ -#define CONFIG_MAGIC 0xEFEFFEFE -#define TOGGLE_VALID 0x0000 +#define NOZOMI_CONFIG_MAGIC 0xEFEFFEFE +#define TOGGLE_VALID 0x0000 /* Definition of interrupt tokens */ #define MDM_DL1 0x0001 @@ -660,9 +660,9 @@ static int nozomi_read_config_table(struct nozomi *dc) read_mem32((u32 *) &dc->config_table, dc->base_addr + 0, sizeof(struct config_table)); - if (dc->config_table.signature != CONFIG_MAGIC) { + if (dc->config_table.signature != NOZOMI_CONFIG_MAGIC) { dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n", - dc->config_table.signature, CONFIG_MAGIC); + dc->config_table.signature, NOZOMI_CONFIG_MAGIC); return 0; } diff --git a/kernel/drivers/tty/pty.c b/kernel/drivers/tty/pty.c index 4d5e84097..78e983677 100644 --- a/kernel/drivers/tty/pty.c +++ b/kernel/drivers/tty/pty.c @@ -7,7 +7,6 @@ */ #include <linux/module.h> - #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/tty.h> @@ -26,6 +25,12 @@ #include <linux/mutex.h> #include <linux/poll.h> +#undef TTY_DEBUG_HANGUP +#ifdef TTY_DEBUG_HANGUP +# define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args) +#else +# define tty_debug_hangup(tty, f, args...) do {} while (0) +#endif #ifdef CONFIG_UNIX98_PTYS static struct tty_driver *ptm_driver; @@ -495,6 +500,10 @@ static int pty_bsd_ioctl(struct tty_struct *tty, } static int legacy_count = CONFIG_LEGACY_PTY_COUNT; +/* + * not really modular, but the easiest way to keep compat with existing + * bootargs behaviour is to continue using module_param here. + */ module_param(legacy_count, int, 0); /* @@ -672,7 +681,14 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) /* this is called once with whichever end is closed last */ static void pty_unix98_shutdown(struct tty_struct *tty) { - devpts_kill_index(tty->driver_data, tty->index); + struct inode *ptmx_inode; + + if (tty->driver->subtype == PTY_TYPE_MASTER) + ptmx_inode = tty->driver_data; + else + ptmx_inode = tty->link->driver_data; + devpts_kill_index(ptmx_inode, tty->index); + devpts_del_ref(ptmx_inode); } static const struct tty_operations ptm_unix98_ops = { @@ -764,6 +780,18 @@ static int ptmx_open(struct inode *inode, struct file *filp) set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ tty->driver_data = inode; + /* + * In the case where all references to ptmx inode are dropped and we + * still have /dev/tty opened pointing to the master/slave pair (ptmx + * is closed/released before /dev/tty), we must make sure that the inode + * is still valid when we call the final pty_unix98_shutdown, thus we + * hold an additional reference to the ptmx inode. For the same /dev/tty + * last close case, we also need to make sure the super_block isn't + * destroyed (devpts instance unmounted), before /dev/tty is closed and + * on its release devpts_kill_index is called. + */ + devpts_add_ref(inode); + tty_add_file(tty, filp); slave_inode = devpts_pty_new(inode, @@ -779,6 +807,8 @@ static int ptmx_open(struct inode *inode, struct file *filp) if (retval) goto err_release; + tty_debug_hangup(tty, "(tty count=%d)\n", tty->count); + tty_unlock(tty); return 0; err_release: @@ -869,4 +899,4 @@ static int __init pty_init(void) unix98_pty_init(); return 0; } -module_init(pty_init); +device_initcall(pty_init); diff --git a/kernel/drivers/tty/rocket.c b/kernel/drivers/tty/rocket.c index c8dd8dc31..802eac7e5 100644 --- a/kernel/drivers/tty/rocket.c +++ b/kernel/drivers/tty/rocket.c @@ -895,14 +895,6 @@ static int rp_open(struct tty_struct *tty, struct file *filp) if (!page) return -ENOMEM; - if (port->flags & ASYNC_CLOSING) { - retval = wait_for_completion_interruptible(&info->close_wait); - free_page(page); - if (retval) - return retval; - return ((port->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); - } - /* * We must not sleep from here until the port is marked fully in use. */ @@ -1057,7 +1049,6 @@ static void rp_close(struct tty_struct *tty, struct file *filp) mutex_unlock(&port->mutex); tty_port_tty_set(port, NULL); - wake_up_interruptible(&port->close_wait); complete_all(&info->close_wait); atomic_dec(&rp_num_ports_open); @@ -1511,10 +1502,6 @@ static void rp_hangup(struct tty_struct *tty) #endif rp_flush_buffer(tty); spin_lock_irqsave(&info->port.lock, flags); - if (info->port.flags & ASYNC_CLOSING) { - spin_unlock_irqrestore(&info->port.lock, flags); - return; - } if (info->port.count) atomic_dec(&rp_num_ports_open); clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); diff --git a/kernel/drivers/tty/rocket.h b/kernel/drivers/tty/rocket.h index ec863f35f..c11a9392f 100644 --- a/kernel/drivers/tty/rocket.h +++ b/kernel/drivers/tty/rocket.h @@ -44,7 +44,7 @@ struct rocket_version { #define ROCKET_HUP_NOTIFY 0x00000004 #define ROCKET_SPLIT_TERMIOS 0x00000008 #define ROCKET_SPD_MASK 0x00000070 -#define ROCKET_SPD_HI 0x00000010 /* Use 56000 instead of 38400 bps */ +#define ROCKET_SPD_HI 0x00000010 /* Use 57600 instead of 38400 bps */ #define ROCKET_SPD_VHI 0x00000020 /* Use 115200 instead of 38400 bps */ #define ROCKET_SPD_SHI 0x00000030 /* Use 230400 instead of 38400 bps */ #define ROCKET_SPD_WARP 0x00000040 /* Use 460800 instead of 38400 bps */ diff --git a/kernel/drivers/tty/serial/68328serial.c b/kernel/drivers/tty/serial/68328serial.c index 5dc9c4bfa..0140ba4aa 100644 --- a/kernel/drivers/tty/serial/68328serial.c +++ b/kernel/drivers/tty/serial/68328serial.c @@ -508,7 +508,8 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty) int i; cflag = tty->termios.c_cflag; - if (!(port = info->port)) + port = info->port; + if (!port) return; ustcnt = uart->ustcnt; @@ -559,8 +560,8 @@ static void rs_fair_output(void) struct m68k_serial *info = &m68k_soft[0]; char c; - if (info == 0) return; - if (info->xmit_buf == 0) return; + if (info == NULL) return; + if (info->xmit_buf == NULL) return; local_irq_save(flags); left = info->xmit_cnt; @@ -1070,7 +1071,6 @@ static void rs_close(struct tty_struct *tty, struct file * filp) wake_up_interruptible(&port->open_wait); } port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&port->close_wait); local_irq_restore(flags); } diff --git a/kernel/drivers/tty/serial/8250/8250.h b/kernel/drivers/tty/serial/8250/8250.h index c43f74c53..d54dcd87c 100644 --- a/kernel/drivers/tty/serial/8250/8250.h +++ b/kernel/drivers/tty/serial/8250/8250.h @@ -42,9 +42,9 @@ struct uart_8250_dma { size_t rx_size; size_t tx_size; - unsigned char tx_running:1; - unsigned char tx_err: 1; - unsigned char rx_running:1; + unsigned char tx_running; + unsigned char tx_err; + unsigned char rx_running; }; struct old_serial_port { @@ -211,3 +211,14 @@ static inline int ns16550a_goto_highspeed(struct uart_8250_port *up) } return 1; } + +static inline int serial_index(struct uart_port *port) +{ + return port->minor - 64; +} + +#if 0 +#define DEBUG_INTR(fmt...) printk(fmt) +#else +#define DEBUG_INTR(fmt...) do { } while (0) +#endif diff --git a/kernel/drivers/tty/serial/8250/8250_core.c b/kernel/drivers/tty/serial/8250/8250_core.c index 822a2e197..af7701ca4 100644 --- a/kernel/drivers/tty/serial/8250/8250_core.c +++ b/kernel/drivers/tty/serial/8250/8250_core.c @@ -1,25 +1,23 @@ /* - * Driver for 8250/16550-type serial ports + * Universal/legacy driver for 8250/16550-type serial ports * * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. * * Copyright (C) 2001 Russell King. * + * Supports: ISA-compatible 8250/16550 ports + * PNP 8250/16550 ports + * early_serial_setup() ports + * userspace-configurable "phantom" ports + * "serial8250" platform devices + * serial8250_register_8250_port() ports + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * A note about mapbase / membase - * - * mapbase is the physical address of the IO port. - * membase is an 'ioremapped' cookie. */ -#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/ioport.h> @@ -36,14 +34,13 @@ #include <linux/nmi.h> #include <linux/mutex.h> #include <linux/slab.h> -#include <linux/kdb.h> #include <linux/uaccess.h> #include <linux/pm_runtime.h> +#include <linux/io.h> #ifdef CONFIG_SPARC #include <linux/sunserialcore.h> #endif -#include <asm/io.h> #include <asm/irq.h> #include "8250.h" @@ -59,29 +56,9 @@ static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS; static struct uart_driver serial8250_reg; -static int serial_index(struct uart_port *port) -{ - return port->minor - 64; -} - static unsigned int skip_txen_test; /* force skip of txen test at init time */ /* - * Debugging. - */ -#if 0 -#define DEBUG_AUTOCONF(fmt...) printk(fmt) -#else -#define DEBUG_AUTOCONF(fmt...) do { } while (0) -#endif - -#if 0 -#define DEBUG_INTR(fmt...) printk(fmt) -#else -#define DEBUG_INTR(fmt...) do { } while (0) -#endif - -/* * On -rt we can have a more delays, and legitimately * so - so don't drop work spuriously and spam the * syslog: @@ -92,22 +69,6 @@ static unsigned int skip_txen_test; /* force skip of txen test at init time */ # define PASS_LIMIT 512 #endif -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - - -#ifdef CONFIG_SERIAL_8250_DETECT_IRQ -#define CONFIG_SERIAL_DETECT_IRQ 1 -#endif -#ifdef CONFIG_SERIAL_8250_MANY_PORTS -#define CONFIG_SERIAL_MANY_PORTS 1 -#endif - -/* - * HUB6 is always on. This will be removed once the header - * files have been cleaned. - */ -#define CONFIG_HUB6 1 - #include <asm/serial.h> /* * SERIAL_PORT_DFNS tells us about built-in ports that have no @@ -143,1563 +104,6 @@ static struct hlist_head irq_lists[NR_IRQ_HASH]; static DEFINE_MUTEX(hash_mutex); /* Used to walk the hash */ /* - * Here we define the default xmit fifo size used for each type of UART. - */ -static const struct serial8250_config uart_config[] = { - [PORT_UNKNOWN] = { - .name = "unknown", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_8250] = { - .name = "8250", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16450] = { - .name = "16450", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16550] = { - .name = "16550", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16550A] = { - .name = "16550A", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .rxtrig_bytes = {1, 4, 8, 14}, - .flags = UART_CAP_FIFO, - }, - [PORT_CIRRUS] = { - .name = "Cirrus", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16650] = { - .name = "ST16650", - .fifo_size = 1, - .tx_loadsz = 1, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16650V2] = { - .name = "ST16650V2", - .fifo_size = 32, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | - UART_FCR_T_TRIG_00, - .rxtrig_bytes = {8, 16, 24, 28}, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16750] = { - .name = "TI16750", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | - UART_FCR7_64BYTE, - .rxtrig_bytes = {1, 16, 32, 56}, - .flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE, - }, - [PORT_STARTECH] = { - .name = "Startech", - .fifo_size = 1, - .tx_loadsz = 1, - }, - [PORT_16C950] = { - .name = "16C950/954", - .fifo_size = 128, - .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - /* UART_CAP_EFR breaks billionon CF bluetooth card. */ - .flags = UART_CAP_FIFO | UART_CAP_SLEEP, - }, - [PORT_16654] = { - .name = "ST16654", - .fifo_size = 64, - .tx_loadsz = 32, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | - UART_FCR_T_TRIG_10, - .rxtrig_bytes = {8, 16, 56, 60}, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_16850] = { - .name = "XR16850", - .fifo_size = 128, - .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, - }, - [PORT_RSA] = { - .name = "RSA", - .fifo_size = 2048, - .tx_loadsz = 2048, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11, - .flags = UART_CAP_FIFO, - }, - [PORT_NS16550A] = { - .name = "NS16550A", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_NATSEMI, - }, - [PORT_XSCALE] = { - .name = "XScale", - .fifo_size = 32, - .tx_loadsz = 32, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_UUE | UART_CAP_RTOIE, - }, - [PORT_OCTEON] = { - .name = "OCTEON", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO, - }, - [PORT_AR7] = { - .name = "AR7", - .fifo_size = 16, - .tx_loadsz = 16, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_U6_16550A] = { - .name = "U6_16550A", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_TEGRA] = { - .name = "Tegra", - .fifo_size = 32, - .tx_loadsz = 8, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | - UART_FCR_T_TRIG_01, - .rxtrig_bytes = {1, 4, 8, 14}, - .flags = UART_CAP_FIFO | UART_CAP_RTOIE, - }, - [PORT_XR17D15X] = { - .name = "XR17D15X", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP, - }, - [PORT_XR17V35X] = { - .name = "XR17V35X", - .fifo_size = 256, - .tx_loadsz = 256, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 | - UART_FCR_T_TRIG_11, - .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP, - }, - [PORT_LPC3220] = { - .name = "LPC3220", - .fifo_size = 64, - .tx_loadsz = 32, - .fcr = UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO | - UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00, - .flags = UART_CAP_FIFO, - }, - [PORT_BRCM_TRUMANAGE] = { - .name = "TruManage", - .fifo_size = 1, - .tx_loadsz = 1024, - .flags = UART_CAP_HFIFO, - }, - [PORT_8250_CIR] = { - .name = "CIR port" - }, - [PORT_ALTR_16550_F32] = { - .name = "Altera 16550 FIFO32", - .fifo_size = 32, - .tx_loadsz = 32, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_ALTR_16550_F64] = { - .name = "Altera 16550 FIFO64", - .fifo_size = 64, - .tx_loadsz = 64, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, - [PORT_ALTR_16550_F128] = { - .name = "Altera 16550 FIFO128", - .fifo_size = 128, - .tx_loadsz = 128, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, - .flags = UART_CAP_FIFO | UART_CAP_AFE, - }, -/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement -workaround of errata A-008006 which states that tx_loadsz should be -configured less than Maximum supported fifo bytes */ - [PORT_16550A_FSL64] = { - .name = "16550A_FSL64", - .fifo_size = 64, - .tx_loadsz = 63, - .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | - UART_FCR7_64BYTE, - .flags = UART_CAP_FIFO, - }, -}; - -/* Uart divisor latch read */ -static int default_serial_dl_read(struct uart_8250_port *up) -{ - return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; -} - -/* Uart divisor latch write */ -static void default_serial_dl_write(struct uart_8250_port *up, int value) -{ - serial_out(up, UART_DLL, value & 0xff); - serial_out(up, UART_DLM, value >> 8 & 0xff); -} - -#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) - -/* Au1x00/RT288x UART hardware has a weird register layout */ -static const s8 au_io_in_map[8] = { - 0, /* UART_RX */ - 2, /* UART_IER */ - 3, /* UART_IIR */ - 5, /* UART_LCR */ - 6, /* UART_MCR */ - 7, /* UART_LSR */ - 8, /* UART_MSR */ - -1, /* UART_SCR (unmapped) */ -}; - -static const s8 au_io_out_map[8] = { - 1, /* UART_TX */ - 2, /* UART_IER */ - 4, /* UART_FCR */ - 5, /* UART_LCR */ - 6, /* UART_MCR */ - -1, /* UART_LSR (unmapped) */ - -1, /* UART_MSR (unmapped) */ - -1, /* UART_SCR (unmapped) */ -}; - -static unsigned int au_serial_in(struct uart_port *p, int offset) -{ - if (offset >= ARRAY_SIZE(au_io_in_map)) - return UINT_MAX; - offset = au_io_in_map[offset]; - if (offset < 0) - return UINT_MAX; - return __raw_readl(p->membase + (offset << p->regshift)); -} - -static void au_serial_out(struct uart_port *p, int offset, int value) -{ - if (offset >= ARRAY_SIZE(au_io_out_map)) - return; - offset = au_io_out_map[offset]; - if (offset < 0) - return; - __raw_writel(value, p->membase + (offset << p->regshift)); -} - -/* Au1x00 haven't got a standard divisor latch */ -static int au_serial_dl_read(struct uart_8250_port *up) -{ - return __raw_readl(up->port.membase + 0x28); -} - -static void au_serial_dl_write(struct uart_8250_port *up, int value) -{ - __raw_writel(value, up->port.membase + 0x28); -} - -#endif - -static unsigned int hub6_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - outb(p->hub6 - 1 + offset, p->iobase); - return inb(p->iobase + 1); -} - -static void hub6_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - outb(p->hub6 - 1 + offset, p->iobase); - outb(value, p->iobase + 1); -} - -static unsigned int mem_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - return readb(p->membase + offset); -} - -static void mem_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - writeb(value, p->membase + offset); -} - -static void mem32_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - writel(value, p->membase + offset); -} - -static unsigned int mem32_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - return readl(p->membase + offset); -} - -static void mem32be_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - iowrite32be(value, p->membase + offset); -} - -static unsigned int mem32be_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - return ioread32be(p->membase + offset); -} - -static unsigned int io_serial_in(struct uart_port *p, int offset) -{ - offset = offset << p->regshift; - return inb(p->iobase + offset); -} - -static void io_serial_out(struct uart_port *p, int offset, int value) -{ - offset = offset << p->regshift; - outb(value, p->iobase + offset); -} - -static int serial8250_default_handle_irq(struct uart_port *port); -static int exar_handle_irq(struct uart_port *port); - -static void set_io_from_upio(struct uart_port *p) -{ - struct uart_8250_port *up = up_to_u8250p(p); - - up->dl_read = default_serial_dl_read; - up->dl_write = default_serial_dl_write; - - switch (p->iotype) { - case UPIO_HUB6: - p->serial_in = hub6_serial_in; - p->serial_out = hub6_serial_out; - break; - - case UPIO_MEM: - p->serial_in = mem_serial_in; - p->serial_out = mem_serial_out; - break; - - case UPIO_MEM32: - p->serial_in = mem32_serial_in; - p->serial_out = mem32_serial_out; - break; - - case UPIO_MEM32BE: - p->serial_in = mem32be_serial_in; - p->serial_out = mem32be_serial_out; - break; - -#if defined(CONFIG_MIPS_ALCHEMY) || defined(CONFIG_SERIAL_8250_RT288X) - case UPIO_AU: - p->serial_in = au_serial_in; - p->serial_out = au_serial_out; - up->dl_read = au_serial_dl_read; - up->dl_write = au_serial_dl_write; - break; -#endif - - default: - p->serial_in = io_serial_in; - p->serial_out = io_serial_out; - break; - } - /* Remember loaded iotype */ - up->cur_iotype = p->iotype; - p->handle_irq = serial8250_default_handle_irq; -} - -static void -serial_port_out_sync(struct uart_port *p, int offset, int value) -{ - switch (p->iotype) { - case UPIO_MEM: - case UPIO_MEM32: - case UPIO_MEM32BE: - case UPIO_AU: - p->serial_out(p, offset, value); - p->serial_in(p, UART_LCR); /* safe, no side-effects */ - break; - default: - p->serial_out(p, offset, value); - } -} - -/* - * For the 16C950 - */ -static void serial_icr_write(struct uart_8250_port *up, int offset, int value) -{ - serial_out(up, UART_SCR, offset); - serial_out(up, UART_ICR, value); -} - -static unsigned int serial_icr_read(struct uart_8250_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; -} - -/* - * FIFO support. - */ -static void serial8250_clear_fifos(struct uart_8250_port *p) -{ - if (p->capabilities & UART_CAP_FIFO) { - serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(p, UART_FCR, 0); - } -} - -void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) -{ - serial8250_clear_fifos(p); - serial_out(p, UART_FCR, p->fcr); -} -EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); - -void serial8250_rpm_get(struct uart_8250_port *p) -{ - if (!(p->capabilities & UART_CAP_RPM)) - return; - pm_runtime_get_sync(p->port.dev); -} -EXPORT_SYMBOL_GPL(serial8250_rpm_get); - -void serial8250_rpm_put(struct uart_8250_port *p) -{ - if (!(p->capabilities & UART_CAP_RPM)) - return; - pm_runtime_mark_last_busy(p->port.dev); - pm_runtime_put_autosuspend(p->port.dev); -} -EXPORT_SYMBOL_GPL(serial8250_rpm_put); - -/* - * These two wrappers ensure that enable_runtime_pm_tx() can be called more than - * once and disable_runtime_pm_tx() will still disable RPM because the fifo is - * empty and the HW can idle again. - */ -static void serial8250_rpm_get_tx(struct uart_8250_port *p) -{ - unsigned char rpm_active; - - if (!(p->capabilities & UART_CAP_RPM)) - return; - - rpm_active = xchg(&p->rpm_tx_active, 1); - if (rpm_active) - return; - pm_runtime_get_sync(p->port.dev); -} - -static void serial8250_rpm_put_tx(struct uart_8250_port *p) -{ - unsigned char rpm_active; - - if (!(p->capabilities & UART_CAP_RPM)) - return; - - rpm_active = xchg(&p->rpm_tx_active, 0); - if (!rpm_active) - return; - pm_runtime_mark_last_busy(p->port.dev); - pm_runtime_put_autosuspend(p->port.dev); -} - -/* - * IER sleep support. UARTs which have EFRs need the "extended - * capability" bit enabled. Note that on XR16C850s, we need to - * reset LCR to write to IER. - */ -static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) -{ - unsigned char lcr = 0, efr = 0; - /* - * Exar UARTs have a SLEEP register that enables or disables - * each UART to enter sleep mode separately. On the XR17V35x the - * register is accessible to each UART at the UART_EXAR_SLEEP - * offset but the UART channel may only write to the corresponding - * bit. - */ - serial8250_rpm_get(p); - if ((p->port.type == PORT_XR17V35X) || - (p->port.type == PORT_XR17D15X)) { - serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0); - goto out; - } - - if (p->capabilities & UART_CAP_SLEEP) { - if (p->capabilities & UART_CAP_EFR) { - lcr = serial_in(p, UART_LCR); - efr = serial_in(p, UART_EFR); - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(p, UART_EFR, UART_EFR_ECB); - serial_out(p, UART_LCR, 0); - } - serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); - if (p->capabilities & UART_CAP_EFR) { - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(p, UART_EFR, efr); - serial_out(p, UART_LCR, lcr); - } - } -out: - serial8250_rpm_put(p); -} - -#ifdef CONFIG_SERIAL_8250_RSA -/* - * Attempts to turn on the RSA FIFO. Returns zero on failure. - * We set the port uart clock rate if we succeed. - */ -static int __enable_rsa(struct uart_8250_port *up) -{ - unsigned char mode; - int result; - - mode = serial_in(up, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - - if (!result) { - serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); - mode = serial_in(up, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - } - - if (result) - up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; - - return result; -} - -static void enable_rsa(struct uart_8250_port *up) -{ - if (up->port.type == PORT_RSA) { - if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); - __enable_rsa(up); - spin_unlock_irq(&up->port.lock); - } - if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) - serial_out(up, UART_RSA_FRR, 0); - } -} - -/* - * Attempts to turn off the RSA FIFO. Returns zero on failure. - * It is unknown why interrupts were disabled in here. However, - * the caller is expected to preserve this behaviour by grabbing - * the spinlock before calling this function. - */ -static void disable_rsa(struct uart_8250_port *up) -{ - unsigned char mode; - int result; - - if (up->port.type == PORT_RSA && - up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { - spin_lock_irq(&up->port.lock); - - mode = serial_in(up, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - - if (!result) { - serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); - mode = serial_in(up, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - } - - if (result) - up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; - spin_unlock_irq(&up->port.lock); - } -} -#endif /* CONFIG_SERIAL_8250_RSA */ - -/* - * This is a quickie test to see how big the FIFO is. - * It doesn't work at all the time, more's the pity. - */ -static int size_fifo(struct uart_8250_port *up) -{ - unsigned char old_fcr, old_mcr, old_lcr; - unsigned short old_dl; - int count; - - old_lcr = serial_in(up, UART_LCR); - serial_out(up, UART_LCR, 0); - old_fcr = serial_in(up, UART_FCR); - old_mcr = serial_in(up, UART_MCR); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_out(up, UART_MCR, UART_MCR_LOOP); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - old_dl = serial_dl_read(up); - serial_dl_write(up, 0x0001); - serial_out(up, UART_LCR, 0x03); - for (count = 0; count < 256; count++) - serial_out(up, UART_TX, count); - mdelay(20);/* FIXME - schedule_timeout */ - for (count = 0; (serial_in(up, UART_LSR) & UART_LSR_DR) && - (count < 256); count++) - serial_in(up, UART_RX); - serial_out(up, UART_FCR, old_fcr); - serial_out(up, UART_MCR, old_mcr); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_dl_write(up, old_dl); - serial_out(up, UART_LCR, old_lcr); - - return count; -} - -/* - * Read UART ID using the divisor method - set DLL and DLM to zero - * and the revision will be in DLL and device type in DLM. We - * preserve the device state across this. - */ -static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) -{ - unsigned char old_dll, old_dlm, old_lcr; - unsigned int id; - - old_lcr = serial_in(p, UART_LCR); - serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A); - - old_dll = serial_in(p, UART_DLL); - old_dlm = serial_in(p, UART_DLM); - - serial_out(p, UART_DLL, 0); - serial_out(p, UART_DLM, 0); - - id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8; - - serial_out(p, UART_DLL, old_dll); - serial_out(p, UART_DLM, old_dlm); - serial_out(p, UART_LCR, old_lcr); - - return id; -} - -/* - * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. - * When this function is called we know it is at least a StarTech - * 16650 V2, but it might be one of several StarTech UARTs, or one of - * its clones. (We treat the broken original StarTech 16650 V1 as a - * 16550, and why not? Startech doesn't seem to even acknowledge its - * existence.) - * - * What evil have men's minds wrought... - */ -static void autoconfig_has_efr(struct uart_8250_port *up) -{ - unsigned int id1, id2, id3, rev; - - /* - * Everything with an EFR has SLEEP - */ - up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; - - /* - * First we check to see if it's an Oxford Semiconductor UART. - * - * If we have to do this here because some non-National - * Semiconductor clone chips lock up if you try writing to the - * LSR register (which serial_icr_read does) - */ - - /* - * Check for Oxford Semiconductor 16C950. - * - * EFR [4] must be set else this test fails. - * - * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca) - * claims that it's needed for 952 dual UART's (which are not - * recommended for new designs). - */ - up->acr = 0; - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, UART_EFR_ECB); - serial_out(up, UART_LCR, 0x00); - id1 = serial_icr_read(up, UART_ID1); - id2 = serial_icr_read(up, UART_ID2); - id3 = serial_icr_read(up, UART_ID3); - rev = serial_icr_read(up, UART_REV); - - DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev); - - if (id1 == 0x16 && id2 == 0xC9 && - (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) { - up->port.type = PORT_16C950; - - /* - * Enable work around for the Oxford Semiconductor 952 rev B - * chip which causes it to seriously miscalculate baud rates - * when DLL is 0. - */ - if (id3 == 0x52 && rev == 0x01) - up->bugs |= UART_BUG_QUOT; - return; - } - - /* - * We check for a XR16C850 by setting DLL and DLM to 0, and then - * reading back DLL and DLM. The chip type depends on the DLM - * value read back: - * 0x10 - XR16C850 and the DLL contains the chip revision. - * 0x12 - XR16C2850. - * 0x14 - XR16C854. - */ - id1 = autoconfig_read_divisor_id(up); - DEBUG_AUTOCONF("850id=%04x ", id1); - - id2 = id1 >> 8; - if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) { - up->port.type = PORT_16850; - return; - } - - /* - * It wasn't an XR16C850. - * - * We distinguish between the '654 and the '650 by counting - * how many bytes are in the FIFO. I'm using this for now, - * since that's the technique that was sent to me in the - * serial driver update, but I'm not convinced this works. - * I've had problems doing this in the past. -TYT - */ - if (size_fifo(up) == 64) - up->port.type = PORT_16654; - else - up->port.type = PORT_16650V2; -} - -/* - * We detected a chip without a FIFO. Only two fall into - * this category - the original 8250 and the 16450. The - * 16450 has a scratch register (accessible with LCR=0) - */ -static void autoconfig_8250(struct uart_8250_port *up) -{ - unsigned char scratch, status1, status2; - - up->port.type = PORT_8250; - - scratch = serial_in(up, UART_SCR); - serial_out(up, UART_SCR, 0xa5); - status1 = serial_in(up, UART_SCR); - serial_out(up, UART_SCR, 0x5a); - status2 = serial_in(up, UART_SCR); - serial_out(up, UART_SCR, scratch); - - if (status1 == 0xa5 && status2 == 0x5a) - up->port.type = PORT_16450; -} - -static int broken_efr(struct uart_8250_port *up) -{ - /* - * Exar ST16C2550 "A2" devices incorrectly detect as - * having an EFR, and report an ID of 0x0201. See - * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html - */ - if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) - return 1; - - return 0; -} - -/* - * We know that the chip has FIFOs. Does it have an EFR? The - * EFR is located in the same register position as the IIR and - * we know the top two bits of the IIR are currently set. The - * EFR should contain zero. Try to read the EFR. - */ -static void autoconfig_16550a(struct uart_8250_port *up) -{ - unsigned char status1, status2; - unsigned int iersave; - - up->port.type = PORT_16550A; - up->capabilities |= UART_CAP_FIFO; - - /* - * XR17V35x UARTs have an extra divisor register, DLD - * that gets enabled with when DLAB is set which will - * cause the device to incorrectly match and assign - * port type to PORT_16650. The EFR for this UART is - * found at offset 0x09. Instead check the Deice ID (DVID) - * register for a 2, 4 or 8 port UART. - */ - if (up->port.flags & UPF_EXAR_EFR) { - status1 = serial_in(up, UART_EXAR_DVID); - if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) { - DEBUG_AUTOCONF("Exar XR17V35x "); - up->port.type = PORT_XR17V35X; - up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP; - - return; - } - - } - - /* - * Check for presence of the EFR when DLAB is set. - * Only ST16C650V1 UARTs pass this test. - */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - if (serial_in(up, UART_EFR) == 0) { - serial_out(up, UART_EFR, 0xA8); - if (serial_in(up, UART_EFR) != 0) { - DEBUG_AUTOCONF("EFRv1 "); - up->port.type = PORT_16650; - up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; - } else { - serial_out(up, UART_LCR, 0); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR7_64BYTE); - status1 = serial_in(up, UART_IIR) >> 5; - serial_out(up, UART_FCR, 0); - serial_out(up, UART_LCR, 0); - - if (status1 == 7) - up->port.type = PORT_16550A_FSL64; - else - DEBUG_AUTOCONF("Motorola 8xxx DUART "); - } - serial_out(up, UART_EFR, 0); - return; - } - - /* - * Maybe it requires 0xbf to be written to the LCR. - * (other ST16C650V2 UARTs, TI16C752A, etc) - */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { - DEBUG_AUTOCONF("EFRv2 "); - autoconfig_has_efr(up); - return; - } - - /* - * Check for a National Semiconductor SuperIO chip. - * Attempt to switch to bank 2, read the value of the LOOP bit - * from EXCR1. Switch back to bank 0, change it in MCR. Then - * switch back to bank 2, read it from EXCR1 again and check - * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 - */ - serial_out(up, UART_LCR, 0); - status1 = serial_in(up, UART_MCR); - serial_out(up, UART_LCR, 0xE0); - status2 = serial_in(up, 0x02); /* EXCR1 */ - - if (!((status2 ^ status1) & UART_MCR_LOOP)) { - serial_out(up, UART_LCR, 0); - serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP); - serial_out(up, UART_LCR, 0xE0); - status2 = serial_in(up, 0x02); /* EXCR1 */ - serial_out(up, UART_LCR, 0); - serial_out(up, UART_MCR, status1); - - if ((status2 ^ status1) & UART_MCR_LOOP) { - unsigned short quot; - - serial_out(up, UART_LCR, 0xE0); - - quot = serial_dl_read(up); - quot <<= 3; - - if (ns16550a_goto_highspeed(up)) - serial_dl_write(up, quot); - - serial_out(up, UART_LCR, 0); - - up->port.uartclk = 921600*16; - up->port.type = PORT_NS16550A; - up->capabilities |= UART_NATSEMI; - return; - } - } - - /* - * No EFR. Try to detect a TI16750, which only sets bit 5 of - * the IIR when 64 byte FIFO mode is enabled when DLAB is set. - * Try setting it with and without DLAB set. Cheap clones - * set bit 5 without DLAB set. - */ - serial_out(up, UART_LCR, 0); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - status1 = serial_in(up, UART_IIR) >> 5; - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - status2 = serial_in(up, UART_IIR) >> 5; - serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_out(up, UART_LCR, 0); - - DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); - - if (status1 == 6 && status2 == 7) { - up->port.type = PORT_16750; - up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP; - return; - } - - /* - * Try writing and reading the UART_IER_UUE bit (b6). - * If it works, this is probably one of the Xscale platform's - * internal UARTs. - * We're going to explicitly set the UUE bit to 0 before - * trying to write and read a 1 just to make sure it's not - * already a 1 and maybe locked there before we even start start. - */ - iersave = serial_in(up, UART_IER); - serial_out(up, UART_IER, iersave & ~UART_IER_UUE); - if (!(serial_in(up, UART_IER) & UART_IER_UUE)) { - /* - * OK it's in a known zero state, try writing and reading - * without disturbing the current state of the other bits. - */ - serial_out(up, UART_IER, iersave | UART_IER_UUE); - if (serial_in(up, UART_IER) & UART_IER_UUE) { - /* - * It's an Xscale. - * We'll leave the UART_IER_UUE bit set to 1 (enabled). - */ - DEBUG_AUTOCONF("Xscale "); - up->port.type = PORT_XSCALE; - up->capabilities |= UART_CAP_UUE | UART_CAP_RTOIE; - return; - } - } else { - /* - * If we got here we couldn't force the IER_UUE bit to 0. - * Log it and continue. - */ - DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); - } - serial_out(up, UART_IER, iersave); - - /* - * Exar uarts have EFR in a weird location - */ - if (up->port.flags & UPF_EXAR_EFR) { - DEBUG_AUTOCONF("Exar XR17D15x "); - up->port.type = PORT_XR17D15X; - up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | - UART_CAP_SLEEP; - - return; - } - - /* - * We distinguish between 16550A and U6 16550A by counting - * how many bytes are in the FIFO. - */ - if (up->port.type == PORT_16550A && size_fifo(up) == 64) { - up->port.type = PORT_U6_16550A; - up->capabilities |= UART_CAP_AFE; - } -} - -/* - * This routine is called by rs_init() to initialize a specific serial - * port. It determines what type of UART chip this serial port is - * using: 8250, 16450, 16550, 16550A. The important question is - * whether or not this UART is a 16550A or not, since this will - * determine whether or not we can use its FIFO features or not. - */ -static void autoconfig(struct uart_8250_port *up) -{ - unsigned char status1, scratch, scratch2, scratch3; - unsigned char save_lcr, save_mcr; - struct uart_port *port = &up->port; - unsigned long flags; - unsigned int old_capabilities; - - if (!port->iobase && !port->mapbase && !port->membase) - return; - - DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ", - serial_index(port), port->iobase, port->membase); - - /* - * We really do need global IRQs disabled here - we're going to - * be frobbing the chips IRQ enable register to see if it exists. - */ - spin_lock_irqsave(&port->lock, flags); - - up->capabilities = 0; - up->bugs = 0; - - if (!(port->flags & UPF_BUGGY_UART)) { - /* - * Do a simple existence test first; if we fail this, - * there's no point trying anything else. - * - * 0x80 is used as a nonsense port to prevent against - * false positives due to ISA bus float. The - * assumption is that 0x80 is a non-existent port; - * which should be safe since include/asm/io.h also - * makes this assumption. - * - * Note: this is safe as long as MCR bit 4 is clear - * and the device is in "PC" mode. - */ - scratch = serial_in(up, UART_IER); - serial_out(up, UART_IER, 0); -#ifdef __i386__ - outb(0xff, 0x080); -#endif - /* - * Mask out IER[7:4] bits for test as some UARTs (e.g. TL - * 16C754B) allow only to modify them if an EFR bit is set. - */ - scratch2 = serial_in(up, UART_IER) & 0x0f; - serial_out(up, UART_IER, 0x0F); -#ifdef __i386__ - outb(0, 0x080); -#endif - scratch3 = serial_in(up, UART_IER) & 0x0f; - serial_out(up, UART_IER, scratch); - if (scratch2 != 0 || scratch3 != 0x0F) { - /* - * We failed; there's nothing here - */ - spin_unlock_irqrestore(&port->lock, flags); - DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", - scratch2, scratch3); - goto out; - } - } - - save_mcr = serial_in(up, UART_MCR); - save_lcr = serial_in(up, UART_LCR); - - /* - * Check to see if a UART is really there. Certain broken - * internal modems based on the Rockwell chipset fail this - * test, because they apparently don't implement the loopback - * test mode. So this test is skipped on the COM 1 through - * COM 4 ports. This *should* be safe, since no board - * manufacturer would be stupid enough to design a board - * that conflicts with COM 1-4 --- we hope! - */ - if (!(port->flags & UPF_SKIP_TEST)) { - 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) { - spin_unlock_irqrestore(&port->lock, flags); - DEBUG_AUTOCONF("LOOP test failed (%02x) ", - status1); - goto out; - } - } - - /* - * We're pretty sure there's a port here. Lets find out what - * type of port it is. The IIR top two bits allows us to find - * out if it's 8250 or 16450, 16550, 16550A or later. This - * determines what we test for next. - * - * We also initialise the EFR (if any) to zero for later. The - * EFR occupies the same register location as the FCR and IIR. - */ - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - serial_out(up, UART_EFR, 0); - 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: - autoconfig_8250(up); - break; - case 1: - port->type = PORT_UNKNOWN; - break; - case 2: - port->type = PORT_16550; - break; - case 3: - autoconfig_16550a(up); - break; - } - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * Only probe for RSA ports if we got the region. - */ - if (port->type == PORT_16550A && up->probe & UART_PROBE_RSA && - __enable_rsa(up)) - port->type = PORT_RSA; -#endif - - serial_out(up, UART_LCR, save_lcr); - - port->fifosize = uart_config[up->port.type].fifo_size; - old_capabilities = up->capabilities; - up->capabilities = uart_config[port->type].flags; - up->tx_loadsz = uart_config[port->type].tx_loadsz; - - if (port->type == PORT_UNKNOWN) - goto out_lock; - - /* - * Reset the UART. - */ -#ifdef CONFIG_SERIAL_8250_RSA - if (port->type == PORT_RSA) - serial_out(up, UART_RSA_FRR, 0); -#endif - serial_out(up, UART_MCR, save_mcr); - serial8250_clear_fifos(up); - serial_in(up, UART_RX); - if (up->capabilities & UART_CAP_UUE) - serial_out(up, UART_IER, UART_IER_UUE); - else - serial_out(up, UART_IER, 0); - -out_lock: - spin_unlock_irqrestore(&port->lock, flags); - if (up->capabilities != old_capabilities) { - printk(KERN_WARNING - "ttyS%d: detected caps %08x should be %08x\n", - serial_index(port), old_capabilities, - up->capabilities); - } -out: - DEBUG_AUTOCONF("iir=%d ", scratch); - DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name); -} - -static void autoconfig_irq(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - unsigned char save_mcr, save_ier; - unsigned char save_ICP = 0; - unsigned int ICP = 0; - unsigned long irqs; - int irq; - - if (port->flags & UPF_FOURPORT) { - ICP = (port->iobase & 0xfe0) | 0x1f; - save_ICP = inb_p(ICP); - outb_p(0x80, ICP); - inb_p(ICP); - } - - /* forget possible initially masked and pending IRQ */ - probe_irq_off(probe_irq_on()); - save_mcr = serial_in(up, UART_MCR); - save_ier = serial_in(up, UART_IER); - serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); - - irqs = probe_irq_on(); - serial_out(up, UART_MCR, 0); - udelay(10); - if (port->flags & UPF_FOURPORT) { - serial_out(up, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS); - } else { - serial_out(up, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); - } - serial_out(up, UART_IER, 0x0f); /* enable all intrs */ - serial_in(up, UART_LSR); - serial_in(up, UART_RX); - serial_in(up, UART_IIR); - serial_in(up, UART_MSR); - serial_out(up, UART_TX, 0xFF); - udelay(20); - irq = probe_irq_off(irqs); - - serial_out(up, UART_MCR, save_mcr); - serial_out(up, UART_IER, save_ier); - - if (port->flags & UPF_FOURPORT) - outb_p(save_ICP, ICP); - - port->irq = (irq > 0) ? irq : 0; -} - -static inline void __stop_tx(struct uart_8250_port *p) -{ - if (p->ier & UART_IER_THRI) { - p->ier &= ~UART_IER_THRI; - serial_out(p, UART_IER, p->ier); - serial8250_rpm_put_tx(p); - } -} - -static void serial8250_stop_tx(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - serial8250_rpm_get(up); - __stop_tx(up); - - /* - * We really want to stop the transmitter from sending. - */ - if (port->type == PORT_16C950) { - up->acr |= UART_ACR_TXDIS; - serial_icr_write(up, UART_ACR, up->acr); - } - serial8250_rpm_put(up); -} - -static void serial8250_start_tx(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - serial8250_rpm_get_tx(up); - - if (up->dma && !up->dma->tx_dma(up)) - return; - - if (!(up->ier & UART_IER_THRI)) { - up->ier |= UART_IER_THRI; - serial_port_out(port, UART_IER, up->ier); - - if (up->bugs & UART_BUG_TXEN) { - unsigned char lsr; - lsr = serial_in(up, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - if (lsr & UART_LSR_THRE) - serial8250_tx_chars(up); - } - } - - /* - * Re-enable the transmitter if we disabled it. - */ - if (port->type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { - up->acr &= ~UART_ACR_TXDIS; - serial_icr_write(up, UART_ACR, up->acr); - } -} - -static void serial8250_throttle(struct uart_port *port) -{ - port->throttle(port); -} - -static void serial8250_unthrottle(struct uart_port *port) -{ - port->unthrottle(port); -} - -static void serial8250_stop_rx(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(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); -} - -static void serial8250_disable_ms(struct uart_port *port) -{ - struct uart_8250_port *up = - container_of(port, struct uart_8250_port, port); - - /* no MSR capabilities */ - if (up->bugs & UART_BUG_NOMSR) - return; - - up->ier &= ~UART_IER_MSI; - serial_port_out(port, UART_IER, up->ier); -} - -static void serial8250_enable_ms(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - /* no MSR capabilities */ - if (up->bugs & UART_BUG_NOMSR) - return; - - up->ier |= UART_IER_MSI; - - serial8250_rpm_get(up); - serial_port_out(port, UART_IER, up->ier); - serial8250_rpm_put(up); -} - -/* - * serial8250_rx_chars: processes according to the passed in LSR - * value, and returns the remaining LSR bits not handled - * by this Rx routine. - */ -unsigned char -serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) -{ - struct uart_port *port = &up->port; - unsigned char ch; - int max_count = 256; - char flag; - - do { - if (likely(lsr & UART_LSR_DR)) - ch = serial_in(up, UART_RX); - else - /* - * Intel 82571 has a Serial Over Lan device that will - * set UART_LSR_BI without setting UART_LSR_DR when - * it receives a break. To avoid reading from the - * receive buffer without UART_LSR_DR bit set, we - * just force the read character to be 0 - */ - ch = 0; - - flag = TTY_NORMAL; - port->icount.rx++; - - lsr |= up->lsr_saved_flags; - up->lsr_saved_flags = 0; - - if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { - if (lsr & UART_LSR_BI) { - lsr &= ~(UART_LSR_FE | UART_LSR_PE); - port->icount.brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ - if (uart_handle_break(port)) - goto ignore_char; - } else if (lsr & UART_LSR_PE) - port->icount.parity++; - else if (lsr & UART_LSR_FE) - port->icount.frame++; - if (lsr & UART_LSR_OE) - port->icount.overrun++; - - /* - * Mask off conditions which should be ignored. - */ - lsr &= port->read_status_mask; - - if (lsr & UART_LSR_BI) { - DEBUG_INTR("handling break...."); - flag = TTY_BREAK; - } else if (lsr & UART_LSR_PE) - flag = TTY_PARITY; - else if (lsr & UART_LSR_FE) - flag = TTY_FRAME; - } - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); - -ignore_char: - lsr = serial_in(up, UART_LSR); - } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0)); - spin_unlock(&port->lock); - tty_flip_buffer_push(&port->state->port); - spin_lock(&port->lock); - return lsr; -} -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; - int count; - - if (port->x_char) { - serial_out(up, UART_TX, port->x_char); - port->icount.tx++; - port->x_char = 0; - return; - } - if (uart_tx_stopped(port)) { - serial8250_stop_tx(port); - return; - } - if (uart_circ_empty(xmit)) { - __stop_tx(up); - return; - } - - count = up->tx_loadsz; - do { - serial_out(up, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - if (uart_circ_empty(xmit)) - break; - if (up->capabilities & UART_CAP_HFIFO) { - if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) != - BOTH_EMPTY) - break; - } - } while (--count > 0); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - DEBUG_INTR("THRE..."); - - /* - * With RPM enabled, we have to wait until the FIFO is empty before 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)) - __stop_tx(up); -} -EXPORT_SYMBOL_GPL(serial8250_tx_chars); - -/* Caller holds uart port lock */ -unsigned int serial8250_modem_status(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - unsigned int status = serial_in(up, UART_MSR); - - status |= up->msr_saved_flags; - up->msr_saved_flags = 0; - if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && - port->state != NULL) { - if (status & UART_MSR_TERI) - port->icount.rng++; - if (status & UART_MSR_DDSR) - port->icount.dsr++; - if (status & UART_MSR_DDCD) - uart_handle_dcd_change(port, status & UART_MSR_DCD); - if (status & UART_MSR_DCTS) - uart_handle_cts_change(port, status & UART_MSR_CTS); - - wake_up_interruptible(&port->state->port.delta_msr_wait); - } - - return status; -} -EXPORT_SYMBOL_GPL(serial8250_modem_status); - -/* - * This handles the interrupt from one port. - */ -int serial8250_handle_irq(struct uart_port *port, unsigned int iir) -{ - unsigned char status; - unsigned long flags; - struct uart_8250_port *up = up_to_u8250p(port); - int dma_err = 0; - - if (iir & UART_IIR_NO_INT) - return 0; - - spin_lock_irqsave(&port->lock, flags); - - status = serial_port_in(port, UART_LSR); - - DEBUG_INTR("status = %x...", status); - - if (status & (UART_LSR_DR | UART_LSR_BI)) { - if (up->dma) - dma_err = up->dma->rx_dma(up, iir); - - if (!up->dma || dma_err) - status = serial8250_rx_chars(up, status); - } - serial8250_modem_status(up); - if ((!up->dma || (up->dma && up->dma->tx_err)) && - (status & UART_LSR_THRE)) - serial8250_tx_chars(up); - - spin_unlock_irqrestore(&port->lock, flags); - return 1; -} -EXPORT_SYMBOL_GPL(serial8250_handle_irq); - -static int serial8250_default_handle_irq(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned int iir; - int ret; - - serial8250_rpm_get(up); - - iir = serial_port_in(port, UART_IIR); - ret = serial8250_handle_irq(port, iir); - - serial8250_rpm_put(up); - return ret; -} - -/* - * These Exar UARTs have an extra interrupt indicator that could - * fire for a few unimplemented interrupts. One of which is a - * wakeup event when coming out of sleep. Put this here just - * to be on the safe side that these interrupts don't go unhandled. - */ -static int exar_handle_irq(struct uart_port *port) -{ - unsigned char int0, int1, int2, int3; - unsigned int iir = serial_port_in(port, UART_IIR); - int ret; - - ret = serial8250_handle_irq(port, iir); - - if ((port->type == PORT_XR17V35X) || - (port->type == PORT_XR17D15X)) { - int0 = serial_port_in(port, 0x80); - int1 = serial_port_in(port, 0x81); - int2 = serial_port_in(port, 0x82); - int3 = serial_port_in(port, 0x83); - } - - return ret; -} - -/* * This is the serial driver's interrupt routine. * * Arjan thinks the old way was overly complex, so it got simplified. @@ -1964,875 +368,6 @@ static void univ8250_release_irq(struct uart_8250_port *up) serial_unlink_irq_chain(up); } -static unsigned int serial8250_tx_empty(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - unsigned int lsr; - - serial8250_rpm_get(up); - - spin_lock_irqsave(&port->lock, flags); - lsr = serial_port_in(port, UART_LSR); - up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; - spin_unlock_irqrestore(&port->lock, flags); - - serial8250_rpm_put(up); - - return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; -} - -static unsigned int serial8250_get_mctrl(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned int status; - unsigned int ret; - - serial8250_rpm_get(up); - status = serial8250_modem_status(up); - serial8250_rpm_put(up); - - ret = 0; - if (status & UART_MSR_DCD) - ret |= TIOCM_CAR; - if (status & UART_MSR_RI) - ret |= TIOCM_RNG; - if (status & UART_MSR_DSR) - ret |= TIOCM_DSR; - if (status & UART_MSR_CTS) - ret |= TIOCM_CTS; - return ret; -} - -void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned char mcr = 0; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; - - serial_port_out(port, UART_MCR, mcr); -} -EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl); - -static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) -{ - if (port->set_mctrl) - return port->set_mctrl(port, mctrl); - return serial8250_do_set_mctrl(port, mctrl); -} - -static void serial8250_break_ctl(struct uart_port *port, int break_state) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - - serial8250_rpm_get(up); - spin_lock_irqsave(&port->lock, flags); - if (break_state == -1) - up->lcr |= UART_LCR_SBC; - else - up->lcr &= ~UART_LCR_SBC; - serial_port_out(port, UART_LCR, up->lcr); - spin_unlock_irqrestore(&port->lock, flags); - serial8250_rpm_put(up); -} - -/* - * Wait for transmitter & holding register to empty - */ -static void wait_for_xmitr(struct uart_8250_port *up, int bits) -{ - unsigned int status, tmout = 10000; - - /* Wait up to 10ms for the character(s) to be sent. */ - for (;;) { - status = serial_in(up, UART_LSR); - - up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; - - if ((status & bits) == bits) - break; - if (--tmout == 0) - break; - udelay(1); - } - - /* Wait up to 1s for flow control if necessary */ - if (up->port.flags & UPF_CONS_FLOW) { - unsigned int tmout; - for (tmout = 1000000; tmout; tmout--) { - unsigned int msr = serial_in(up, UART_MSR); - up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; - if (msr & UART_MSR_CTS) - break; - udelay(1); - touch_nmi_watchdog(); - } - } -} - -#ifdef CONFIG_CONSOLE_POLL -/* - * Console polling routines for writing and reading from the uart while - * in an interrupt or debug context. - */ - -static int serial8250_get_poll_char(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned char lsr; - int status; - - serial8250_rpm_get(up); - - lsr = serial_port_in(port, UART_LSR); - - if (!(lsr & UART_LSR_DR)) { - status = NO_POLL_CHAR; - goto out; - } - - status = serial_port_in(port, UART_RX); -out: - serial8250_rpm_put(up); - return status; -} - - -static void serial8250_put_poll_char(struct uart_port *port, - unsigned char c) -{ - unsigned int ier; - struct uart_8250_port *up = up_to_u8250p(port); - - serial8250_rpm_get(up); - /* - * First save the IER then disable the interrupts - */ - ier = serial_port_in(port, UART_IER); - if (up->capabilities & UART_CAP_UUE) - serial_port_out(port, UART_IER, UART_IER_UUE); - else - serial_port_out(port, UART_IER, 0); - - wait_for_xmitr(up, BOTH_EMPTY); - /* - * Send the character out. - */ - serial_port_out(port, UART_TX, c); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up, BOTH_EMPTY); - serial_port_out(port, UART_IER, ier); - serial8250_rpm_put(up); -} - -#endif /* CONFIG_CONSOLE_POLL */ - -int serial8250_do_startup(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - unsigned char lsr, iir; - int retval; - - if (port->type == PORT_8250_CIR) - return -ENODEV; - - if (!port->fifosize) - port->fifosize = uart_config[port->type].fifo_size; - if (!up->tx_loadsz) - up->tx_loadsz = uart_config[port->type].tx_loadsz; - if (!up->capabilities) - up->capabilities = uart_config[port->type].flags; - up->mcr = 0; - - if (port->iotype != up->cur_iotype) - set_io_from_upio(port); - - serial8250_rpm_get(up); - if (port->type == PORT_16C950) { - /* Wake up and initialize UART */ - up->acr = 0; - serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); - serial_port_out(port, UART_EFR, UART_EFR_ECB); - serial_port_out(port, UART_IER, 0); - serial_port_out(port, UART_LCR, 0); - serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ - serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); - serial_port_out(port, UART_EFR, UART_EFR_ECB); - serial_port_out(port, UART_LCR, 0); - } - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * If this is an RSA port, see if we can kick it up to the - * higher speed clock. - */ - enable_rsa(up); -#endif - /* - * Clear the FIFO buffers and disable them. - * (they will be reenabled in set_termios()) - */ - serial8250_clear_fifos(up); - - /* - * Clear the interrupt registers. - */ - serial_port_in(port, UART_LSR); - serial_port_in(port, UART_RX); - serial_port_in(port, UART_IIR); - serial_port_in(port, UART_MSR); - - /* - * At this point, there's no way the LSR could still be 0xff; - * if it is, then bail out, because there's likely no UART - * here. - */ - if (!(port->flags & UPF_BUGGY_UART) && - (serial_port_in(port, UART_LSR) == 0xff)) { - printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", - serial_index(port)); - retval = -ENODEV; - goto out; - } - - /* - * For a XR16C850, we need to set the trigger levels - */ - if (port->type == PORT_16850) { - unsigned char fctr; - - serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); - - fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); - serial_port_out(port, UART_FCTR, - fctr | UART_FCTR_TRGD | UART_FCTR_RX); - serial_port_out(port, UART_TRG, UART_TRG_96); - serial_port_out(port, UART_FCTR, - fctr | UART_FCTR_TRGD | UART_FCTR_TX); - serial_port_out(port, UART_TRG, UART_TRG_96); - - serial_port_out(port, UART_LCR, 0); - } - - if (port->irq) { - unsigned char iir1; - /* - * Test for UARTs that do not reassert THRE when the - * transmitter is idle and the interrupt has already - * been cleared. Real 16550s should always reassert - * this interrupt whenever the transmitter is idle and - * the interrupt is enabled. Delays are necessary to - * allow register changes to become visible. - */ - spin_lock_irqsave(&port->lock, flags); - if (up->port.irqflags & IRQF_SHARED) - disable_irq_nosync(port->irq); - - wait_for_xmitr(up, UART_LSR_THRE); - serial_port_out_sync(port, UART_IER, UART_IER_THRI); - udelay(1); /* allow THRE to set */ - iir1 = serial_port_in(port, UART_IIR); - serial_port_out(port, UART_IER, 0); - serial_port_out_sync(port, UART_IER, UART_IER_THRI); - udelay(1); /* allow a working UART time to re-assert THRE */ - iir = serial_port_in(port, UART_IIR); - serial_port_out(port, UART_IER, 0); - - if (port->irqflags & IRQF_SHARED) - enable_irq(port->irq); - spin_unlock_irqrestore(&port->lock, flags); - - /* - * If the interrupt is not reasserted, or we otherwise - * don't trust the iir, setup a timer to kick the UART - * on a regular basis. - */ - if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || - up->port.flags & UPF_BUG_THRE) { - up->bugs |= UART_BUG_THRE; - } - } - - retval = up->ops->setup_irq(up); - if (retval) - goto out; - - /* - * Now, initialize the UART - */ - serial_port_out(port, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irqsave(&port->lock, flags); - if (up->port.flags & UPF_FOURPORT) { - if (!up->port.irq) - up->port.mctrl |= TIOCM_OUT1; - } else - /* - * Most PC uarts need OUT2 raised to enable interrupts. - */ - if (port->irq) - up->port.mctrl |= TIOCM_OUT2; - - serial8250_set_mctrl(port, port->mctrl); - - /* Serial over Lan (SoL) hack: - Intel 8257x Gigabit ethernet chips have a - 16550 emulation, to be used for Serial Over Lan. - Those chips take a longer time than a normal - serial device to signalize that a transmission - data was queued. Due to that, the above test generally - fails. One solution would be to delay the reading of - iir. However, this is not reliable, since the timeout - is variable. So, let's just don't test if we receive - TX irq. This way, we'll never enable UART_BUG_TXEN. - */ - if (up->port.flags & UPF_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 (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { - if (!(up->bugs & UART_BUG_TXEN)) { - up->bugs |= UART_BUG_TXEN; - pr_debug("ttyS%d - enabling bad tx status workarounds\n", - serial_index(port)); - } - } else { - up->bugs &= ~UART_BUG_TXEN; - } - -dont_test_tx_en: - spin_unlock_irqrestore(&port->lock, flags); - - /* - * Clear the interrupt registers again for luck, and clear the - * saved flags to avoid getting false values from polling - * routines or the previous session. - */ - serial_port_in(port, UART_LSR); - serial_port_in(port, UART_RX); - serial_port_in(port, UART_IIR); - serial_port_in(port, UART_MSR); - up->lsr_saved_flags = 0; - up->msr_saved_flags = 0; - - /* - * Request DMA channels for both RX and TX. - */ - if (up->dma) { - retval = serial8250_request_dma(up); - if (retval) { - pr_warn_ratelimited("ttyS%d - failed to request DMA\n", - serial_index(port)); - up->dma = NULL; - } - } - - /* - * Finally, enable interrupts. Note: Modem status interrupts - * are set via set_termios(), which will be occurring imminently - * anyway, so we don't enable them here. - */ - up->ier = UART_IER_RLSI | UART_IER_RDI; - serial_port_out(port, UART_IER, up->ier); - - if (port->flags & UPF_FOURPORT) { - unsigned int icp; - /* - * Enable interrupts on the AST Fourport board - */ - icp = (port->iobase & 0xfe0) | 0x01f; - outb_p(0x80, icp); - inb_p(icp); - } - retval = 0; -out: - serial8250_rpm_put(up); - return retval; -} -EXPORT_SYMBOL_GPL(serial8250_do_startup); - -static int serial8250_startup(struct uart_port *port) -{ - if (port->startup) - return port->startup(port); - return serial8250_do_startup(port); -} - -void serial8250_do_shutdown(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned long flags; - - serial8250_rpm_get(up); - /* - * Disable interrupts from this port - */ - up->ier = 0; - serial_port_out(port, UART_IER, 0); - - if (up->dma) - serial8250_release_dma(up); - - spin_lock_irqsave(&port->lock, flags); - if (port->flags & UPF_FOURPORT) { - /* reset interrupts on the AST Fourport board */ - inb((port->iobase & 0xfe0) | 0x1f); - port->mctrl |= TIOCM_OUT1; - } else - port->mctrl &= ~TIOCM_OUT2; - - serial8250_set_mctrl(port, port->mctrl); - spin_unlock_irqrestore(&port->lock, flags); - - /* - * Disable break condition and FIFOs - */ - serial_port_out(port, UART_LCR, - serial_port_in(port, UART_LCR) & ~UART_LCR_SBC); - serial8250_clear_fifos(up); - -#ifdef CONFIG_SERIAL_8250_RSA - /* - * Reset the RSA board back to 115kbps compat mode. - */ - disable_rsa(up); -#endif - - /* - * Read data port to reset things, and then unlink from - * the IRQ chain. - */ - serial_port_in(port, UART_RX); - serial8250_rpm_put(up); - - up->ops->release_irq(up); -} -EXPORT_SYMBOL_GPL(serial8250_do_shutdown); - -static void serial8250_shutdown(struct uart_port *port) -{ - if (port->shutdown) - port->shutdown(port); - else - serial8250_do_shutdown(port); -} - -/* - * XR17V35x UARTs have an extra fractional divisor register (DLD) - * Calculate divisor with extra 4-bit fractional portion - */ -static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up, - unsigned int baud, - unsigned int *frac) -{ - struct uart_port *port = &up->port; - unsigned int quot_16; - - quot_16 = DIV_ROUND_CLOSEST(port->uartclk, baud); - *frac = quot_16 & 0x0f; - - return quot_16 >> 4; -} - -static unsigned int serial8250_get_divisor(struct uart_8250_port *up, - unsigned int baud, - unsigned int *frac) -{ - struct uart_port *port = &up->port; - unsigned int quot; - - /* - * Handle magic divisors for baud rates above baud_base on - * SMSC SuperIO chips. - * - */ - if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/4)) - quot = 0x8001; - else if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/8)) - quot = 0x8002; - else if (up->port.type == PORT_XR17V35X) - quot = xr17v35x_get_divisor(up, baud, frac); - else - quot = uart_get_divisor(port, baud); - - /* - * Oxford Semi 952 rev B workaround - */ - if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0) - quot++; - - return quot; -} - -static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, - tcflag_t c_cflag) -{ - unsigned char cval; - - switch (c_cflag & CSIZE) { - case CS5: - cval = UART_LCR_WLEN5; - break; - case CS6: - cval = UART_LCR_WLEN6; - break; - case CS7: - cval = UART_LCR_WLEN7; - break; - default: - case CS8: - cval = UART_LCR_WLEN8; - break; - } - - if (c_cflag & CSTOPB) - cval |= UART_LCR_STOP; - if (c_cflag & PARENB) { - cval |= UART_LCR_PARITY; - if (up->bugs & UART_BUG_PARITY) - up->fifo_bug = true; - } - if (!(c_cflag & PARODD)) - cval |= UART_LCR_EPAR; -#ifdef CMSPAR - if (c_cflag & CMSPAR) - cval |= UART_LCR_SPAR; -#endif - - return cval; -} - -static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, - unsigned int quot, unsigned int quot_frac) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - /* Workaround to enable 115200 baud on OMAP1510 internal ports */ - if (is_omap1510_8250(up)) { - if (baud == 115200) { - quot = 1; - serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1); - } else - serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0); - } - - /* - * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2, - * otherwise just set DLAB - */ - if (up->capabilities & UART_NATSEMI) - serial_port_out(port, UART_LCR, 0xe0); - else - serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); - - serial_dl_write(up, quot); - - /* XR17V35x UARTs have an extra fractional divisor register (DLD) */ - if (up->port.type == PORT_XR17V35X) - serial_port_out(port, 0x2, quot_frac); -} - -void -serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - struct uart_8250_port *up = up_to_u8250p(port); - unsigned char cval; - unsigned long flags; - unsigned int baud, quot, frac = 0; - - cval = serial8250_compute_lcr(up, termios->c_cflag); - - /* - * Ask the core to calculate the divisor for us. - */ - baud = uart_get_baud_rate(port, termios, old, - port->uartclk / 16 / 0xffff, - port->uartclk / 16); - quot = serial8250_get_divisor(up, baud, &frac); - - /* - * Ok, we're now changing the port state. Do it with - * interrupts disabled. - */ - serial8250_rpm_get(up); - spin_lock_irqsave(&port->lock, flags); - - up->lcr = cval; /* Save computed LCR */ - - if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { - /* NOTE: If fifo_bug is not set, a user can set RX_trigger. */ - if ((baud < 2400 && !up->dma) || up->fifo_bug) { - up->fcr &= ~UART_FCR_TRIGGER_MASK; - up->fcr |= UART_FCR_TRIGGER_1; - } - } - - /* - * MCR-based auto flow control. When AFE is enabled, RTS will be - * deasserted when the receive FIFO contains more characters than - * the trigger, or the MCR RTS bit is cleared. In the case where - * the remote UART is not using CTS auto flow control, we must - * have sufficient FIFO entries for the latency of the remote - * UART to respond. IOW, at least 32 bytes of FIFO. - */ - if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { - up->mcr &= ~UART_MCR_AFE; - if (termios->c_cflag & CRTSCTS) - up->mcr |= UART_MCR_AFE; - } - - /* - * Update the per-port timeout. - */ - uart_update_timeout(port, termios->c_cflag, baud); - - port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | 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)) - port->read_status_mask |= UART_LSR_BI; - - /* - * Characteres to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART_LSR_OE; - } - - /* - * ignore all characters if CREAD is not set - */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_LSR_DR; - - /* - * CTS flow control flag and modem status interrupts - */ - up->ier &= ~UART_IER_MSI; - if (!(up->bugs & UART_BUG_NOMSR) && - UART_ENABLE_MS(&up->port, termios->c_cflag)) - up->ier |= UART_IER_MSI; - if (up->capabilities & UART_CAP_UUE) - up->ier |= UART_IER_UUE; - if (up->capabilities & UART_CAP_RTOIE) - up->ier |= UART_IER_RTOIE; - - serial_port_out(port, UART_IER, up->ier); - - if (up->capabilities & UART_CAP_EFR) { - unsigned char efr = 0; - /* - * TI16C752/Startech hardware flow control. FIXME: - * - TI16C752 requires control thresholds to be set. - * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled. - */ - if (termios->c_cflag & CRTSCTS) - efr |= UART_EFR_CTS; - - serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); - if (port->flags & UPF_EXAR_EFR) - serial_port_out(port, UART_XR_EFR, efr); - else - serial_port_out(port, UART_EFR, efr); - } - - serial8250_set_divisor(port, baud, quot, frac); - - /* - * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR - * is written without DLAB set, this mode will be disabled. - */ - if (port->type == PORT_16750) - serial_port_out(port, UART_FCR, up->fcr); - - serial_port_out(port, UART_LCR, up->lcr); /* reset DLAB */ - if (port->type != PORT_16750) { - /* emulated UARTs (Lucent Venus 167x) need two steps */ - if (up->fcr & UART_FCR_ENABLE_FIFO) - serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_port_out(port, UART_FCR, up->fcr); /* set fcr */ - } - serial8250_set_mctrl(port, port->mctrl); - spin_unlock_irqrestore(&port->lock, flags); - serial8250_rpm_put(up); - - /* Don't rewrite B0 */ - if (tty_termios_baud_rate(termios)) - tty_termios_encode_baud_rate(termios, baud, baud); -} -EXPORT_SYMBOL(serial8250_do_set_termios); - -static void -serial8250_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) -{ - if (port->set_termios) - port->set_termios(port, termios, old); - else - serial8250_do_set_termios(port, termios, old); -} - -static void -serial8250_set_ldisc(struct uart_port *port, struct ktermios *termios) -{ - if (termios->c_line == N_PPS) { - port->flags |= UPF_HARDPPS_CD; - spin_lock_irq(&port->lock); - serial8250_enable_ms(port); - spin_unlock_irq(&port->lock); - } else { - port->flags &= ~UPF_HARDPPS_CD; - if (!UART_ENABLE_MS(port, termios->c_cflag)) { - spin_lock_irq(&port->lock); - serial8250_disable_ms(port); - spin_unlock_irq(&port->lock); - } - } -} - - -void serial8250_do_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - struct uart_8250_port *p = up_to_u8250p(port); - - serial8250_set_sleep(p, state != 0); -} -EXPORT_SYMBOL(serial8250_do_pm); - -static void -serial8250_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) -{ - if (port->pm) - port->pm(port, state, oldstate); - else - serial8250_do_pm(port, state, oldstate); -} - -static unsigned int serial8250_port_size(struct uart_8250_port *pt) -{ - if (pt->port.mapsize) - return pt->port.mapsize; - if (pt->port.iotype == UPIO_AU) { - if (pt->port.type == PORT_RT2880) - return 0x100; - return 0x1000; - } - if (is_omap1_8250(pt)) - return 0x16 << pt->port.regshift; - - return 8 << pt->port.regshift; -} - -/* - * Resource handling. - */ -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: - case UPIO_TSI: - case UPIO_MEM32: - case UPIO_MEM32BE: - case UPIO_MEM: - if (!port->mapbase) - break; - - if (!request_mem_region(port->mapbase, size, "serial")) { - ret = -EBUSY; - break; - } - - if (port->flags & UPF_IOREMAP) { - port->membase = ioremap_nocache(port->mapbase, size); - if (!port->membase) { - release_mem_region(port->mapbase, size); - ret = -ENOMEM; - } - } - break; - - case UPIO_HUB6: - case UPIO_PORT: - if (!request_region(port->iobase, size, "serial")) - ret = -EBUSY; - break; - } - return ret; -} - -static void serial8250_release_std_resource(struct uart_8250_port *up) -{ - unsigned int size = serial8250_port_size(up); - struct uart_port *port = &up->port; - - switch (port->iotype) { - case UPIO_AU: - case UPIO_TSI: - case UPIO_MEM32: - case UPIO_MEM32BE: - case UPIO_MEM: - if (!port->mapbase) - break; - - if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); - port->membase = NULL; - } - - release_mem_region(port->mapbase, size); - break; - - case UPIO_HUB6: - case UPIO_PORT: - release_region(port->iobase, size); - break; - } -} - #ifdef CONFIG_SERIAL_8250_RSA static int serial8250_request_rsa_resource(struct uart_8250_port *up) { @@ -2870,259 +405,6 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up) } #endif -static void serial8250_release_port(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - serial8250_release_std_resource(up); -} - -static int serial8250_request_port(struct uart_port *port) -{ - struct uart_8250_port *up = up_to_u8250p(port); - int ret; - - if (port->type == PORT_8250_CIR) - return -ENODEV; - - ret = serial8250_request_std_resource(up); - - return ret; -} - -static int fcr_get_rxtrig_bytes(struct uart_8250_port *up) -{ - const struct serial8250_config *conf_type = &uart_config[up->port.type]; - unsigned char bytes; - - bytes = conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(up->fcr)]; - - return bytes ? bytes : -EOPNOTSUPP; -} - -static int bytes_to_fcr_rxtrig(struct uart_8250_port *up, unsigned char bytes) -{ - const struct serial8250_config *conf_type = &uart_config[up->port.type]; - int i; - - if (!conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(UART_FCR_R_TRIG_00)]) - return -EOPNOTSUPP; - - for (i = 1; i < UART_FCR_R_TRIG_MAX_STATE; i++) { - if (bytes < conf_type->rxtrig_bytes[i]) - /* Use the nearest lower value */ - return (--i) << UART_FCR_R_TRIG_SHIFT; - } - - return UART_FCR_R_TRIG_11; -} - -static int do_get_rxtrig(struct tty_port *port) -{ - struct uart_state *state = container_of(port, struct uart_state, port); - struct uart_port *uport = state->uart_port; - struct uart_8250_port *up = - container_of(uport, struct uart_8250_port, port); - - if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1) - return -EINVAL; - - return fcr_get_rxtrig_bytes(up); -} - -static int do_serial8250_get_rxtrig(struct tty_port *port) -{ - int rxtrig_bytes; - - mutex_lock(&port->mutex); - rxtrig_bytes = do_get_rxtrig(port); - mutex_unlock(&port->mutex); - - return rxtrig_bytes; -} - -static ssize_t serial8250_get_attr_rx_trig_bytes(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct tty_port *port = dev_get_drvdata(dev); - int rxtrig_bytes; - - rxtrig_bytes = do_serial8250_get_rxtrig(port); - if (rxtrig_bytes < 0) - return rxtrig_bytes; - - return snprintf(buf, PAGE_SIZE, "%d\n", rxtrig_bytes); -} - -static int do_set_rxtrig(struct tty_port *port, unsigned char bytes) -{ - struct uart_state *state = container_of(port, struct uart_state, port); - struct uart_port *uport = state->uart_port; - struct uart_8250_port *up = - container_of(uport, struct uart_8250_port, port); - int rxtrig; - - if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 || - up->fifo_bug) - return -EINVAL; - - rxtrig = bytes_to_fcr_rxtrig(up, bytes); - if (rxtrig < 0) - return rxtrig; - - serial8250_clear_fifos(up); - up->fcr &= ~UART_FCR_TRIGGER_MASK; - up->fcr |= (unsigned char)rxtrig; - serial_out(up, UART_FCR, up->fcr); - return 0; -} - -static int do_serial8250_set_rxtrig(struct tty_port *port, unsigned char bytes) -{ - int ret; - - mutex_lock(&port->mutex); - ret = do_set_rxtrig(port, bytes); - mutex_unlock(&port->mutex); - - return ret; -} - -static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct tty_port *port = dev_get_drvdata(dev); - unsigned char bytes; - int ret; - - if (!count) - return -EINVAL; - - ret = kstrtou8(buf, 10, &bytes); - if (ret < 0) - return ret; - - ret = do_serial8250_set_rxtrig(port, bytes); - if (ret < 0) - return ret; - - return count; -} - -static DEVICE_ATTR(rx_trig_bytes, S_IRUSR | S_IWUSR | S_IRGRP, - serial8250_get_attr_rx_trig_bytes, - serial8250_set_attr_rx_trig_bytes); - -static struct attribute *serial8250_dev_attrs[] = { - &dev_attr_rx_trig_bytes.attr, - NULL, - }; - -static struct attribute_group serial8250_dev_attr_group = { - .attrs = serial8250_dev_attrs, - }; - -static void register_dev_spec_attr_grp(struct uart_8250_port *up) -{ - const struct serial8250_config *conf_type = &uart_config[up->port.type]; - - if (conf_type->rxtrig_bytes[0]) - up->port.attr_group = &serial8250_dev_attr_group; -} - -static void serial8250_config_port(struct uart_port *port, int flags) -{ - struct uart_8250_port *up = up_to_u8250p(port); - int ret; - - if (port->type == PORT_8250_CIR) - return; - - /* - * Find the region that we can probe for. This in turn - * tells us whether we can probe for the type of port. - */ - ret = serial8250_request_std_resource(up); - if (ret < 0) - return; - - if (port->iotype != up->cur_iotype) - set_io_from_upio(port); - - if (flags & UART_CONFIG_TYPE) - autoconfig(up); - - /* if access method is AU, it is a 16550 with a quirk */ - if (port->type == PORT_16550A && port->iotype == UPIO_AU) - up->bugs |= UART_BUG_NOMSR; - - /* HW bugs may trigger IRQ while IIR == NO_INT */ - if (port->type == PORT_TEGRA) - up->bugs |= UART_BUG_NOMSR; - - if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) - autoconfig_irq(up); - - if (port->type == PORT_UNKNOWN) - serial8250_release_std_resource(up); - - /* Fixme: probably not the best place for this */ - if ((port->type == PORT_XR17V35X) || - (port->type == PORT_XR17D15X)) - port->handle_irq = exar_handle_irq; - - register_dev_spec_attr_grp(up); - up->fcr = uart_config[up->port.type].fcr; -} - -static int -serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) -{ - if (ser->irq >= 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) - return -EINVAL; - return 0; -} - -static const char * -serial8250_type(struct uart_port *port) -{ - int type = port->type; - - if (type >= ARRAY_SIZE(uart_config)) - type = 0; - return uart_config[type].name; -} - -static const struct uart_ops serial8250_pops = { - .tx_empty = serial8250_tx_empty, - .set_mctrl = serial8250_set_mctrl, - .get_mctrl = serial8250_get_mctrl, - .stop_tx = serial8250_stop_tx, - .start_tx = serial8250_start_tx, - .throttle = serial8250_throttle, - .unthrottle = serial8250_unthrottle, - .stop_rx = serial8250_stop_rx, - .enable_ms = serial8250_enable_ms, - .break_ctl = serial8250_break_ctl, - .startup = serial8250_startup, - .shutdown = serial8250_shutdown, - .set_termios = serial8250_set_termios, - .set_ldisc = serial8250_set_ldisc, - .pm = serial8250_pm, - .type = serial8250_type, - .release_port = serial8250_release_port, - .request_port = serial8250_request_port, - .config_port = serial8250_config_port, - .verify_port = serial8250_verify_port, -#ifdef CONFIG_CONSOLE_POLL - .poll_get_char = serial8250_get_poll_char, - .poll_put_char = serial8250_put_poll_char, -#endif -}; - static const struct uart_ops *base_ops; static struct uart_ops univ8250_port_ops; @@ -3161,42 +443,6 @@ void serial8250_set_isa_configurator( } EXPORT_SYMBOL(serial8250_set_isa_configurator); -static void serial8250_init_port(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - - spin_lock_init(&port->lock); - port->ops = &serial8250_pops; - - up->cur_iotype = 0xFF; -} - -static void serial8250_set_defaults(struct uart_8250_port *up) -{ - struct uart_port *port = &up->port; - - if (up->port.flags & UPF_FIXED_TYPE) { - unsigned int type = up->port.type; - - if (!up->port.fifosize) - up->port.fifosize = uart_config[type].fifo_size; - if (!up->tx_loadsz) - up->tx_loadsz = uart_config[type].tx_loadsz; - if (!up->capabilities) - up->capabilities = uart_config[type].flags; - } - - set_io_from_upio(port); - - /* default dma handlers */ - if (up->dma) { - if (!up->dma->tx_dma) - up->dma->tx_dma = serial8250_tx_dma; - if (!up->dma->rx_dma) - up->dma->rx_dma = serial8250_rx_dma; - } -} - #ifdef CONFIG_SERIAL_8250_RSA static void univ8250_config_port(struct uart_port *port, int flags) @@ -3332,6 +578,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) for (i = 0; i < nr_uarts; i++) { struct uart_8250_port *up = &serial8250_ports[i]; + if (up->port.type == PORT_8250_CIR) + continue; + if (up->port.dev) continue; @@ -3346,94 +595,6 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) #ifdef CONFIG_SERIAL_8250_CONSOLE -static void serial8250_console_putchar(struct uart_port *port, int ch) -{ - struct uart_8250_port *up = up_to_u8250p(port); - - wait_for_xmitr(up, UART_LSR_THRE); - serial_port_out(port, UART_TX, ch); -} - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console_lock must be held when we get here. - */ -static void serial8250_console_write(struct uart_8250_port *up, const char *s, - unsigned int count) -{ - struct uart_port *port = &up->port; - unsigned long flags; - unsigned int ier; - int locked = 1; - - touch_nmi_watchdog(); - - serial8250_rpm_get(up); - - if (port->sysrq) - locked = 0; - else if (oops_in_progress || in_kdb_printk()) - locked = spin_trylock_irqsave(&port->lock, flags); - else - spin_lock_irqsave(&port->lock, flags); - - /* - * First save the IER then disable the interrupts - */ - ier = serial_port_in(port, UART_IER); - - if (up->capabilities & UART_CAP_UUE) - serial_port_out(port, UART_IER, UART_IER_UUE); - else - serial_port_out(port, UART_IER, 0); - - /* check scratch reg to see if port powered off during system sleep */ - if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { - struct ktermios termios; - unsigned int baud, quot, frac = 0; - - termios.c_cflag = port->cons->cflag; - if (port->state->port.tty && termios.c_cflag == 0) - termios.c_cflag = port->state->port.tty->termios.c_cflag; - - baud = uart_get_baud_rate(port, &termios, NULL, - port->uartclk / 16 / 0xffff, - port->uartclk / 16); - quot = serial8250_get_divisor(up, baud, &frac); - - serial8250_set_divisor(port, baud, quot, frac); - serial_port_out(port, UART_LCR, up->lcr); - serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); - - up->canary = 0; - } - - uart_console_write(port, s, count, serial8250_console_putchar); - - /* - * Finally, wait for transmitter to become empty - * and restore the IER - */ - wait_for_xmitr(up, BOTH_EMPTY); - serial_port_out(port, UART_IER, ier); - - /* - * The receive handling will happen properly because the - * receive ready bit will still be set; it is not cleared - * on read. However, modem control will not, we must - * call it if we have saved something in the saved flags - * while processing with interrupts off. - */ - if (up->msr_saved_flags) - serial8250_modem_status(up); - - if (locked) - spin_unlock_irqrestore(&port->lock, flags); - serial8250_rpm_put(up); -} - static void univ8250_console_write(struct console *co, const char *s, unsigned int count) { @@ -3442,39 +603,6 @@ static void univ8250_console_write(struct console *co, const char *s, serial8250_console_write(up, s, count); } -static unsigned int probe_baud(struct uart_port *port) -{ - unsigned char lcr, dll, dlm; - unsigned int quot; - - lcr = serial_port_in(port, UART_LCR); - serial_port_out(port, UART_LCR, lcr | UART_LCR_DLAB); - dll = serial_port_in(port, UART_DLL); - dlm = serial_port_in(port, UART_DLM); - serial_port_out(port, UART_LCR, lcr); - - quot = (dlm << 8) | dll; - return (port->uartclk / 16) / quot; -} - -static int serial8250_console_setup(struct uart_port *port, char *options, bool probe) -{ - int baud = 9600; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (!port->iobase && !port->membase) - return -ENODEV; - - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else if (probe) - baud = probe_baud(port); - - return uart_set_options(port, port->cons, baud, parity, bits, flow); -} - static int univ8250_console_setup(struct console *co, char *options) { struct uart_port *port; @@ -3558,6 +686,9 @@ static struct console univ8250_console = { static int __init univ8250_console_init(void) { + if (nr_uarts == 0) + return -ENODEV; + serial8250_isa_init_ports(); register_console(&univ8250_console); return 0; @@ -3588,7 +719,7 @@ int __init early_serial_setup(struct uart_port *port) { struct uart_port *p; - if (port->line >= ARRAY_SIZE(serial8250_ports)) + if (port->line >= ARRAY_SIZE(serial8250_ports) || nr_uarts == 0) return -ENODEV; serial8250_isa_init_ports(); @@ -3860,7 +991,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up) uart->port.mapbase = up->port.mapbase; uart->port.mapsize = up->port.mapsize; uart->port.private_data = up->port.private_data; - uart->port.fifosize = up->port.fifosize; uart->tx_loadsz = up->tx_loadsz; uart->capabilities = up->capabilities; uart->port.throttle = up->port.throttle; @@ -3909,13 +1039,24 @@ int serial8250_register_8250_port(struct uart_8250_port *up) if (up->dl_write) uart->dl_write = up->dl_write; - if (serial8250_isa_config != NULL) - serial8250_isa_config(0, &uart->port, - &uart->capabilities); + if (uart->port.type != PORT_8250_CIR) { + if (serial8250_isa_config != NULL) + serial8250_isa_config(0, &uart->port, + &uart->capabilities); + + ret = uart_add_one_port(&serial8250_reg, + &uart->port); + if (ret == 0) + ret = uart->port.line; + } else { + dev_info(uart->port.dev, + "skipping CIR port at 0x%lx / 0x%llx, IRQ %d\n", + uart->port.iobase, + (unsigned long long)uart->port.mapbase, + uart->port.irq); - ret = uart_add_one_port(&serial8250_reg, &uart->port); - if (ret == 0) - ret = uart->port.line; + ret = 0; + } } mutex_unlock(&serial_mutex); @@ -3955,6 +1096,9 @@ static int __init serial8250_init(void) { int ret; + if (nr_uarts == 0) + return -ENODEV; + serial8250_isa_init_ports(); printk(KERN_INFO "Serial: 8250/16550 driver, " diff --git a/kernel/drivers/tty/serial/8250/8250_dma.c b/kernel/drivers/tty/serial/8250/8250_dma.c index 21d01a491..78259d3c6 100644 --- a/kernel/drivers/tty/serial/8250/8250_dma.c +++ b/kernel/drivers/tty/serial/8250/8250_dma.c @@ -54,9 +54,6 @@ static void __dma_rx_complete(void *param) struct dma_tx_state state; int count; - dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr, - dma->rx_size, DMA_FROM_DEVICE); - dma->rx_running = 0; dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); @@ -80,10 +77,6 @@ int serial8250_tx_dma(struct uart_8250_port *p) return 0; dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); - if (dma->tx_size < p->port.fifosize) { - ret = -EINVAL; - goto err; - } desc = dmaengine_prep_slave_single(dma->txchan, dma->tx_addr + xmit->tail, @@ -156,9 +149,6 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir) dma->rx_cookie = dmaengine_submit(desc); - dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr, - dma->rx_size, DMA_FROM_DEVICE); - dma_async_issue_pending(dma->rxchan); return 0; diff --git a/kernel/drivers/tty/serial/8250/8250_dw.c b/kernel/drivers/tty/serial/8250/8250_dw.c index 176f18f2e..a5d319e4a 100644 --- a/kernel/drivers/tty/serial/8250/8250_dw.c +++ b/kernel/drivers/tty/serial/8250/8250_dw.c @@ -56,7 +56,6 @@ struct dw8250_data { u8 usr_reg; - int last_mcr; int line; int msr_mask_on; int msr_mask_off; @@ -64,6 +63,9 @@ struct dw8250_data { struct clk *pclk; struct reset_control *rst; struct uart_8250_dma dma; + + unsigned int skip_autocfg:1; + unsigned int uart_16550_compatible:1; }; #define BYT_PRV_CLK 0x800 @@ -76,12 +78,6 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; - /* If reading MSR, report CTS asserted when auto-CTS/RTS enabled */ - if (offset == UART_MSR && d->last_mcr & UART_MCR_AFE) { - value |= UART_MSR_CTS; - value &= ~UART_MSR_DCTS; - } - /* Override any modem control signals if needed */ if (offset == UART_MSR) { value |= d->msr_mask_on; @@ -101,11 +97,6 @@ static void dw8250_force_idle(struct uart_port *p) static void dw8250_serial_out(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; - - if (offset == UART_MCR) - d->last_mcr = value; - writeb(value, p->membase + (offset << p->regshift)); /* Make sure LCR write wasn't ignored */ @@ -144,11 +135,6 @@ static unsigned int dw8250_serial_inq(struct uart_port *p, int offset) static void dw8250_serial_outq(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; - - if (offset == UART_MCR) - d->last_mcr = value; - value &= 0xff; __raw_writeq(value, p->membase + (offset << p->regshift)); /* Read back to ensure register write ordering. */ @@ -175,11 +161,6 @@ static void dw8250_serial_outq(struct uart_port *p, int offset, int value) static void dw8250_serial_out32(struct uart_port *p, int offset, int value) { - struct dw8250_data *d = p->private_data; - - if (offset == UART_MCR) - d->last_mcr = value; - writel(value, p->membase + (offset << p->regshift)); /* Make sure LCR write wasn't ignored */ @@ -246,10 +227,6 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, if (IS_ERR(d->clk) || !old) goto out; - /* Not requesting clock rates below 1.8432Mhz */ - if (baud < 115200) - baud = 115200; - clk_disable_unprepare(d->clk); rate = clk_round_rate(d->clk, baud * 16); ret = clk_set_rate(d->clk, rate); @@ -257,28 +234,86 @@ static void dw8250_set_termios(struct uart_port *p, struct ktermios *termios, if (!ret) p->uartclk = rate; + + p->status &= ~UPSTAT_AUTOCTS; + if (termios->c_cflag & CRTSCTS) + p->status |= UPSTAT_AUTOCTS; + out: serial8250_do_set_termios(p, termios, old); } -static bool dw8250_dma_filter(struct dma_chan *chan, void *param) +/* + * dw8250_fallback_dma_filter will prevent the UART from getting just any free + * channel on platforms that have DMA engines, but don't have any channels + * assigned to the UART. + * + * REVISIT: This is a work around for limitation in the DMA Engine API. Once the + * core problem is fixed, this function is no longer needed. + */ +static bool dw8250_fallback_dma_filter(struct dma_chan *chan, void *param) { return false; } -static void dw8250_setup_port(struct uart_8250_port *up) +static bool dw8250_idma_filter(struct dma_chan *chan, void *param) { - struct uart_port *p = &up->port; - u32 reg = readl(p->membase + DW_UART_UCV); + return param == chan->device->dev->parent; +} + +static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) +{ + if (p->dev->of_node) { + struct device_node *np = p->dev->of_node; + int id; + + /* get index of serial line, if found in DT aliases */ + id = of_alias_get_id(np, "serial"); + if (id >= 0) + p->line = id; +#ifdef CONFIG_64BIT + if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) { + p->serial_in = dw8250_serial_inq; + p->serial_out = dw8250_serial_outq; + p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; + p->type = PORT_OCTEON; + data->usr_reg = 0x27; + data->skip_autocfg = true; + } +#endif + } else if (has_acpi_companion(p->dev)) { + p->iotype = UPIO_MEM32; + p->regshift = 2; + p->serial_in = dw8250_serial_in32; + p->set_termios = dw8250_set_termios; + /* So far none of there implement the Busy Functionality */ + data->uart_16550_compatible = true; + } + + /* Platforms with iDMA */ + if (platform_get_resource_byname(to_platform_device(p->dev), + IORESOURCE_MEM, "lpss_priv")) { + p->set_termios = dw8250_set_termios; + data->dma.rx_param = p->dev->parent; + data->dma.tx_param = p->dev->parent; + data->dma.fn = dw8250_idma_filter; + } +} + +static void dw8250_setup_port(struct uart_port *p) +{ + struct uart_8250_port *up = up_to_u8250p(p); + u32 reg; /* * If the Component Version Register returns zero, we know that * ADDITIONAL_FEATURES are not enabled. No need to go any further. */ + reg = readl(p->membase + DW_UART_UCV); if (!reg) return; - dev_dbg_ratelimited(p->dev, "Designware UART version %c.%c%c\n", + dev_dbg(p->dev, "Designware UART version %c.%c%c\n", (reg >> 24) & 0xff, (reg >> 16) & 0xff, (reg >> 8) & 0xff); reg = readl(p->membase + DW_UART_CPR); @@ -290,7 +325,6 @@ static void dw8250_setup_port(struct uart_8250_port *up) p->type = PORT_16550A; p->flags |= UPF_FIXED_TYPE; p->fifosize = DW_UART_CPR_FIFO_SIZE(reg); - up->tx_loadsz = p->fifosize; up->capabilities = UART_CAP_FIFO; } @@ -298,149 +332,91 @@ static void dw8250_setup_port(struct uart_8250_port *up) up->capabilities |= UART_CAP_AFE; } -static int dw8250_probe_of(struct uart_port *p, - struct dw8250_data *data) +static int dw8250_probe(struct platform_device *pdev) { - struct device_node *np = p->dev->of_node; - struct uart_8250_port *up = up_to_u8250p(p); - u32 val; - bool has_ucv = true; - int id; + struct uart_8250_port uart = {}; + struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + int irq = platform_get_irq(pdev, 0); + struct uart_port *p = &uart.port; + struct dw8250_data *data; + int err; + u32 val; -#ifdef CONFIG_64BIT - if (of_device_is_compatible(np, "cavium,octeon-3860-uart")) { - p->serial_in = dw8250_serial_inq; - p->serial_out = dw8250_serial_outq; - p->flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; - p->type = PORT_OCTEON; - data->usr_reg = 0x27; - has_ucv = false; - } else -#endif - if (!of_property_read_u32(np, "reg-io-width", &val)) { - switch (val) { - case 1: - break; - case 4: - p->iotype = UPIO_MEM32; - p->serial_in = dw8250_serial_in32; - p->serial_out = dw8250_serial_out32; - break; - default: - dev_err(p->dev, "unsupported reg-io-width (%u)\n", val); - return -EINVAL; - } + if (!regs) { + dev_err(&pdev->dev, "no registers defined\n"); + return -EINVAL; } - if (has_ucv) - dw8250_setup_port(up); - /* if we have a valid fifosize, try hooking up DMA here */ - if (p->fifosize) { - up->dma = &data->dma; - - up->dma->rxconf.src_maxburst = p->fifosize / 4; - up->dma->txconf.dst_maxburst = p->fifosize / 4; + if (irq < 0) { + if (irq != -EPROBE_DEFER) + dev_err(&pdev->dev, "cannot get irq\n"); + return irq; } - if (!of_property_read_u32(np, "reg-shift", &val)) + spin_lock_init(&p->lock); + p->mapbase = regs->start; + p->irq = irq; + p->handle_irq = dw8250_handle_irq; + p->pm = dw8250_do_pm; + p->type = PORT_8250; + p->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT; + p->dev = &pdev->dev; + p->iotype = UPIO_MEM; + p->serial_in = dw8250_serial_in; + p->serial_out = dw8250_serial_out; + + p->membase = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); + if (!p->membase) + return -ENOMEM; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dma.fn = dw8250_fallback_dma_filter; + data->usr_reg = DW_UART_USR; + p->private_data = data; + + data->uart_16550_compatible = device_property_read_bool(p->dev, + "snps,uart-16550-compatible"); + + err = device_property_read_u32(p->dev, "reg-shift", &val); + if (!err) p->regshift = val; - /* get index of serial line, if found in DT aliases */ - id = of_alias_get_id(np, "serial"); - if (id >= 0) - p->line = id; + err = device_property_read_u32(p->dev, "reg-io-width", &val); + if (!err && val == 4) { + p->iotype = UPIO_MEM32; + p->serial_in = dw8250_serial_in32; + p->serial_out = dw8250_serial_out32; + } - if (of_property_read_bool(np, "dcd-override")) { + if (device_property_read_bool(p->dev, "dcd-override")) { /* Always report DCD as active */ data->msr_mask_on |= UART_MSR_DCD; data->msr_mask_off |= UART_MSR_DDCD; } - if (of_property_read_bool(np, "dsr-override")) { + if (device_property_read_bool(p->dev, "dsr-override")) { /* Always report DSR as active */ data->msr_mask_on |= UART_MSR_DSR; data->msr_mask_off |= UART_MSR_DDSR; } - if (of_property_read_bool(np, "cts-override")) { + if (device_property_read_bool(p->dev, "cts-override")) { /* Always report CTS as active */ data->msr_mask_on |= UART_MSR_CTS; data->msr_mask_off |= UART_MSR_DCTS; } - if (of_property_read_bool(np, "ri-override")) { + if (device_property_read_bool(p->dev, "ri-override")) { /* Always report Ring indicator as inactive */ data->msr_mask_off |= UART_MSR_RI; data->msr_mask_off |= UART_MSR_TERI; } - return 0; -} - -static int dw8250_probe_acpi(struct uart_8250_port *up, - struct dw8250_data *data) -{ - struct uart_port *p = &up->port; - - dw8250_setup_port(up); - - p->iotype = UPIO_MEM32; - p->serial_in = dw8250_serial_in32; - p->serial_out = dw8250_serial_out32; - p->regshift = 2; - - up->dma = &data->dma; - - up->dma->rxconf.src_maxburst = p->fifosize / 4; - up->dma->txconf.dst_maxburst = p->fifosize / 4; - - up->port.set_termios = dw8250_set_termios; - - return 0; -} - -static int dw8250_probe(struct platform_device *pdev) -{ - struct uart_8250_port uart = {}; - struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - int irq = platform_get_irq(pdev, 0); - struct dw8250_data *data; - int err; - - if (!regs) { - dev_err(&pdev->dev, "no registers defined\n"); - return -EINVAL; - } - - if (irq < 0) { - if (irq != -EPROBE_DEFER) - dev_err(&pdev->dev, "cannot get irq\n"); - return irq; - } - - spin_lock_init(&uart.port.lock); - uart.port.mapbase = regs->start; - uart.port.irq = irq; - uart.port.handle_irq = dw8250_handle_irq; - uart.port.pm = dw8250_do_pm; - uart.port.type = PORT_8250; - uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT; - uart.port.dev = &pdev->dev; - - uart.port.membase = devm_ioremap(&pdev->dev, regs->start, - resource_size(regs)); - if (!uart.port.membase) - return -ENOMEM; - - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->usr_reg = DW_UART_USR; - /* Always ask for fixed clock rate from a property. */ - device_property_read_u32(&pdev->dev, "clock-frequency", - &uart.port.uartclk); + device_property_read_u32(p->dev, "clock-frequency", &p->uartclk); /* If there is separate baudclk, get the rate from it. */ data->clk = devm_clk_get(&pdev->dev, "baudclk"); @@ -454,11 +430,11 @@ static int dw8250_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "could not enable optional baudclk: %d\n", err); else - uart.port.uartclk = clk_get_rate(data->clk); + p->uartclk = clk_get_rate(data->clk); } /* If no clock rate is defined, fail. */ - if (!uart.port.uartclk) { + if (!p->uartclk) { dev_err(&pdev->dev, "clock rate not defined\n"); return -EINVAL; } @@ -484,26 +460,22 @@ static int dw8250_probe(struct platform_device *pdev) if (!IS_ERR(data->rst)) reset_control_deassert(data->rst); - data->dma.rx_param = data; - data->dma.tx_param = data; - data->dma.fn = dw8250_dma_filter; + dw8250_quirks(p, data); - uart.port.iotype = UPIO_MEM; - uart.port.serial_in = dw8250_serial_in; - uart.port.serial_out = dw8250_serial_out; - uart.port.private_data = data; + /* If the Busy Functionality is not implemented, don't handle it */ + if (data->uart_16550_compatible) { + p->serial_out = NULL; + p->handle_irq = NULL; + } - if (pdev->dev.of_node) { - err = dw8250_probe_of(&uart.port, data); - if (err) - goto err_reset; - } else if (ACPI_HANDLE(&pdev->dev)) { - err = dw8250_probe_acpi(&uart, data); - if (err) - goto err_reset; - } else { - err = -ENODEV; - goto err_reset; + if (!data->skip_autocfg) + dw8250_setup_port(p); + + /* If we have a valid fifosize, try hooking up DMA */ + if (p->fifosize) { + data->dma.rxconf.src_maxburst = p->fifosize / 4; + data->dma.txconf.dst_maxburst = p->fifosize / 4; + uart.dma = &data->dma; } data->line = serial8250_register_8250_port(&uart); diff --git a/kernel/drivers/tty/serial/8250/8250_early.c b/kernel/drivers/tty/serial/8250/8250_early.c index 6c0fd8b9d..ceb85792a 100644 --- a/kernel/drivers/tty/serial/8250/8250_early.c +++ b/kernel/drivers/tty/serial/8250/8250_early.c @@ -29,13 +29,15 @@ #include <linux/tty.h> #include <linux/init.h> #include <linux/console.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/serial_reg.h> #include <linux/serial.h> #include <linux/serial_8250.h> #include <asm/io.h> #include <asm/serial.h> -unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offset) +static unsigned int __init serial8250_early_in(struct uart_port *port, int offset) { switch (port->iotype) { case UPIO_MEM: @@ -51,7 +53,7 @@ unsigned int __weak __init serial8250_early_in(struct uart_port *port, int offse } } -void __weak __init serial8250_early_out(struct uart_port *port, int offset, int value) +static void __init serial8250_early_out(struct uart_port *port, int offset, int value) { switch (port->iotype) { case UPIO_MEM: @@ -131,7 +133,7 @@ static void __init init_port(struct earlycon_device *device) serial8250_early_out(port, UART_LCR, c & ~UART_LCR_DLAB); } -static int __init early_serial8250_setup(struct earlycon_device *device, +int __init early_serial8250_setup(struct earlycon_device *device, const char *options) { if (!(device->port.membase || device->port.iobase)) @@ -152,3 +154,5 @@ static int __init early_serial8250_setup(struct earlycon_device *device, } EARLYCON_DECLARE(uart8250, early_serial8250_setup); EARLYCON_DECLARE(uart, early_serial8250_setup); +OF_EARLYCON_DECLARE(ns16550, "ns16550", early_serial8250_setup); +OF_EARLYCON_DECLARE(ns16550a, "ns16550a", early_serial8250_setup); diff --git a/kernel/drivers/tty/serial/8250/8250_fintek.c b/kernel/drivers/tty/serial/8250/8250_fintek.c index 5815e81b5..89474399a 100644 --- a/kernel/drivers/tty/serial/8250/8250_fintek.c +++ b/kernel/drivers/tty/serial/8250/8250_fintek.c @@ -17,18 +17,19 @@ #include <linux/serial_core.h> #include "8250.h" -#define ADDR_PORT 0x4E -#define DATA_PORT 0x4F -#define ENTRY_KEY 0x77 +#define ADDR_PORT 0 +#define DATA_PORT 1 #define EXIT_KEY 0xAA #define CHIP_ID1 0x20 -#define CHIP_ID1_VAL 0x02 #define CHIP_ID2 0x21 -#define CHIP_ID2_VAL 0x16 +#define CHIP_ID_0 0x1602 +#define CHIP_ID_1 0x0501 #define VENDOR_ID1 0x23 #define VENDOR_ID1_VAL 0x19 #define VENDOR_ID2 0x24 #define VENDOR_ID2_VAL 0x34 +#define IO_ADDR1 0x61 +#define IO_ADDR2 0x60 #define LDN 0x7 #define RS485 0xF0 @@ -39,51 +40,49 @@ #define DRIVER_NAME "8250_fintek" -static int fintek_8250_enter_key(void){ +struct fintek_8250 { + u16 base_port; + u8 index; + u8 key; + long line; +}; + +static int fintek_8250_enter_key(u16 base_port, u8 key) +{ - if (!request_muxed_region(ADDR_PORT, 2, DRIVER_NAME)) + if (!request_muxed_region(base_port, 2, DRIVER_NAME)) return -EBUSY; - outb(ENTRY_KEY, ADDR_PORT); - outb(ENTRY_KEY, ADDR_PORT); + outb(key, base_port + ADDR_PORT); + outb(key, base_port + ADDR_PORT); return 0; } -static void fintek_8250_exit_key(void){ - - outb(EXIT_KEY, ADDR_PORT); - release_region(ADDR_PORT, 2); -} - -static int fintek_8250_get_index(resource_size_t base_addr) +static void fintek_8250_exit_key(u16 base_port) { - resource_size_t base[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8}; - int i; - - for (i = 0; i < ARRAY_SIZE(base); i++) - if (base_addr == base[i]) - return i; - return -ENODEV; + outb(EXIT_KEY, base_port + ADDR_PORT); + release_region(base_port + ADDR_PORT, 2); } -static int fintek_8250_check_id(void) +static int fintek_8250_check_id(u16 base_port) { + u16 chip; - outb(CHIP_ID1, ADDR_PORT); - if (inb(DATA_PORT) != CHIP_ID1_VAL) + outb(VENDOR_ID1, base_port + ADDR_PORT); + if (inb(base_port + DATA_PORT) != VENDOR_ID1_VAL) return -ENODEV; - outb(CHIP_ID2, ADDR_PORT); - if (inb(DATA_PORT) != CHIP_ID2_VAL) + outb(VENDOR_ID2, base_port + ADDR_PORT); + if (inb(base_port + DATA_PORT) != VENDOR_ID2_VAL) return -ENODEV; - outb(VENDOR_ID1, ADDR_PORT); - if (inb(DATA_PORT) != VENDOR_ID1_VAL) - return -ENODEV; + outb(CHIP_ID1, base_port + ADDR_PORT); + chip = inb(base_port + DATA_PORT); + outb(CHIP_ID2, base_port + ADDR_PORT); + chip |= inb(base_port + DATA_PORT) << 8; - outb(VENDOR_ID2, ADDR_PORT); - if (inb(DATA_PORT) != VENDOR_ID2_VAL) + if (chip != CHIP_ID_0 && chip != CHIP_ID_1) return -ENODEV; return 0; @@ -93,9 +92,9 @@ static int fintek_8250_rs485_config(struct uart_port *port, struct serial_rs485 *rs485) { uint8_t config = 0; - int index = fintek_8250_get_index(port->iobase); + struct fintek_8250 *pdata = port->private_data; - if (index < 0) + if (!pdata) return -EINVAL; if (rs485->flags & SER_RS485_ENABLED) @@ -125,44 +124,84 @@ static int fintek_8250_rs485_config(struct uart_port *port, if (rs485->flags & SER_RS485_RTS_ON_SEND) config |= RTS_INVERT; - if (fintek_8250_enter_key()) + if (fintek_8250_enter_key(pdata->base_port, pdata->key)) return -EBUSY; - outb(LDN, ADDR_PORT); - outb(index, DATA_PORT); - outb(RS485, ADDR_PORT); - outb(config, DATA_PORT); - fintek_8250_exit_key(); + outb(LDN, pdata->base_port + ADDR_PORT); + outb(pdata->index, pdata->base_port + DATA_PORT); + outb(RS485, pdata->base_port + ADDR_PORT); + outb(config, pdata->base_port + DATA_PORT); + fintek_8250_exit_key(pdata->base_port); port->rs485 = *rs485; return 0; } +static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index) +{ + static const u16 addr[] = {0x4e, 0x2e}; + static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67}; + int i, j, k; + + for (i = 0; i < ARRAY_SIZE(addr); i++) { + for (j = 0; j < ARRAY_SIZE(keys); j++) { + + if (fintek_8250_enter_key(addr[i], keys[j])) + continue; + if (fintek_8250_check_id(addr[i])) { + fintek_8250_exit_key(addr[i]); + continue; + } + + for (k = 0; k < 4; k++) { + u16 aux; + + outb(LDN, addr[i] + ADDR_PORT); + outb(k, addr[i] + DATA_PORT); + + outb(IO_ADDR1, addr[i] + ADDR_PORT); + aux = inb(addr[i] + DATA_PORT); + outb(IO_ADDR2, addr[i] + ADDR_PORT); + aux |= inb(addr[i] + DATA_PORT) << 8; + if (aux != io_address) + continue; + + fintek_8250_exit_key(addr[i]); + *key = keys[j]; + *index = k; + return addr[i]; + } + fintek_8250_exit_key(addr[i]); + } + } + + return -ENODEV; +} + static int fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { - int line; struct uart_8250_port uart; - int ret; + struct fintek_8250 *pdata; + int base_port; + u8 key; + u8 index; if (!pnp_port_valid(dev, 0)) return -ENODEV; - if (fintek_8250_get_index(pnp_port_start(dev, 0)) < 0) + base_port = fintek_8250_base_port(pnp_port_start(dev, 0), &key, &index); + if (base_port < 0) return -ENODEV; - /* Enable configuration registers*/ - if (fintek_8250_enter_key()) - return -EBUSY; + memset(&uart, 0, sizeof(uart)); - /*Check ID*/ - ret = fintek_8250_check_id(); - fintek_8250_exit_key(); - if (ret) - return ret; + pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + uart.port.private_data = pdata; - memset(&uart, 0, sizeof(uart)); if (!pnp_irq_valid(dev, 0)) return -ENODEV; uart.port.irq = pnp_irq(dev, 0); @@ -176,40 +215,43 @@ fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) uart.port.uartclk = 1843200; uart.port.dev = &dev->dev; - line = serial8250_register_8250_port(&uart); - if (line < 0) + pdata->key = key; + pdata->base_port = base_port; + pdata->index = index; + pdata->line = serial8250_register_8250_port(&uart); + if (pdata->line < 0) return -ENODEV; - pnp_set_drvdata(dev, (void *)((long)line + 1)); + pnp_set_drvdata(dev, pdata); return 0; } static void fintek_8250_remove(struct pnp_dev *dev) { - long line = (long)pnp_get_drvdata(dev); + struct fintek_8250 *pdata = pnp_get_drvdata(dev); - if (line) - serial8250_unregister_port(line - 1); + if (pdata) + serial8250_unregister_port(pdata->line); } #ifdef CONFIG_PM static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state) { - long line = (long)pnp_get_drvdata(dev); + struct fintek_8250 *pdata = pnp_get_drvdata(dev); - if (!line) + if (!pdata) return -ENODEV; - serial8250_suspend_port(line - 1); + serial8250_suspend_port(pdata->line); return 0; } static int fintek_8250_resume(struct pnp_dev *dev) { - long line = (long)pnp_get_drvdata(dev); + struct fintek_8250 *pdata = pnp_get_drvdata(dev); - if (!line) + if (!pdata) return -ENODEV; - serial8250_resume_port(line - 1); + serial8250_resume_port(pdata->line); return 0; } #else diff --git a/kernel/drivers/tty/serial/8250/8250_fsl.c b/kernel/drivers/tty/serial/8250/8250_fsl.c index c0533a57e..910bfee5a 100644 --- a/kernel/drivers/tty/serial/8250/8250_fsl.c +++ b/kernel/drivers/tty/serial/8250/8250_fsl.c @@ -60,3 +60,4 @@ int fsl8250_handle_irq(struct uart_port *port) spin_unlock_irqrestore(&up->port.lock, flags); return 1; } +EXPORT_SYMBOL_GPL(fsl8250_handle_irq); diff --git a/kernel/drivers/tty/serial/8250/8250_ingenic.c b/kernel/drivers/tty/serial/8250/8250_ingenic.c new file mode 100644 index 000000000..49394b4c5 --- /dev/null +++ b/kernel/drivers/tty/serial/8250/8250_ingenic.c @@ -0,0 +1,345 @@ +/* + * Copyright (C) 2010 Lars-Peter Clausen <lars@metafoo.de> + * Copyright (C) 2015 Imagination Technologies + * + * Ingenic SoC UART support + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/clk.h> +#include <linux/console.h> +#include <linux/io.h> +#include <linux/libfdt.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_fdt.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/serial_8250.h> +#include <linux/serial_core.h> +#include <linux/serial_reg.h> + +#include "8250.h" + +/** ingenic_uart_config: SOC specific config data. */ +struct ingenic_uart_config { + int tx_loadsz; + int fifosize; +}; + +struct ingenic_uart_data { + struct clk *clk_module; + struct clk *clk_baud; + int line; +}; + +static const struct of_device_id of_match[]; + +#define UART_FCR_UME BIT(4) + +#define UART_MCR_MDCE BIT(7) +#define UART_MCR_FCM BIT(6) + +static struct earlycon_device *early_device; + +static uint8_t __init early_in(struct uart_port *port, int offset) +{ + return readl(port->membase + (offset << 2)); +} + +static void __init early_out(struct uart_port *port, int offset, uint8_t value) +{ + writel(value, port->membase + (offset << 2)); +} + +static void __init ingenic_early_console_putc(struct uart_port *port, int c) +{ + uint8_t lsr; + + do { + lsr = early_in(port, UART_LSR); + } while ((lsr & UART_LSR_TEMT) == 0); + + early_out(port, UART_TX, c); +} + +static void __init ingenic_early_console_write(struct console *console, + const char *s, unsigned int count) +{ + uart_console_write(&early_device->port, s, count, + ingenic_early_console_putc); +} + +static void __init ingenic_early_console_setup_clock(struct earlycon_device *dev) +{ + void *fdt = initial_boot_params; + const __be32 *prop; + int offset; + + offset = fdt_path_offset(fdt, "/ext"); + if (offset < 0) + return; + + prop = fdt_getprop(fdt, offset, "clock-frequency", NULL); + if (!prop) + return; + + dev->port.uartclk = be32_to_cpup(prop); +} + +static int __init ingenic_early_console_setup(struct earlycon_device *dev, + const char *opt) +{ + struct uart_port *port = &dev->port; + unsigned int baud, divisor; + + if (!dev->port.membase) + return -ENODEV; + + ingenic_early_console_setup_clock(dev); + + baud = dev->baud ?: 115200; + divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * baud); + + early_out(port, UART_IER, 0); + early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); + early_out(port, UART_DLL, 0); + early_out(port, UART_DLM, 0); + early_out(port, UART_LCR, UART_LCR_WLEN8); + early_out(port, UART_FCR, UART_FCR_UME | UART_FCR_CLEAR_XMIT | + UART_FCR_CLEAR_RCVR | UART_FCR_ENABLE_FIFO); + early_out(port, UART_MCR, UART_MCR_RTS | UART_MCR_DTR); + + early_out(port, UART_LCR, UART_LCR_DLAB | UART_LCR_WLEN8); + early_out(port, UART_DLL, divisor & 0xff); + early_out(port, UART_DLM, (divisor >> 8) & 0xff); + early_out(port, UART_LCR, UART_LCR_WLEN8); + + early_device = dev; + dev->con->write = ingenic_early_console_write; + + return 0; +} + +EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup); +OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart", + ingenic_early_console_setup); + +EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup); +OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart", + ingenic_early_console_setup); + +EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup); +OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart", + ingenic_early_console_setup); + +static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) +{ + int ier; + + switch (offset) { + case UART_FCR: + /* UART module enable */ + value |= UART_FCR_UME; + break; + + case UART_IER: + /* Enable receive timeout interrupt with the + * receive line status interrupt */ + value |= (value & 0x4) << 2; + break; + + case UART_MCR: + /* If we have enabled modem status IRQs we should enable modem + * mode. */ + ier = p->serial_in(p, UART_IER); + + if (ier & UART_IER_MSI) + value |= UART_MCR_MDCE | UART_MCR_FCM; + else + value &= ~(UART_MCR_MDCE | UART_MCR_FCM); + break; + + default: + break; + } + + writeb(value, p->membase + (offset << p->regshift)); +} + +static unsigned int ingenic_uart_serial_in(struct uart_port *p, int offset) +{ + unsigned int value; + + value = readb(p->membase + (offset << p->regshift)); + + /* Hide non-16550 compliant bits from higher levels */ + switch (offset) { + case UART_FCR: + value &= ~UART_FCR_UME; + break; + + case UART_MCR: + value &= ~(UART_MCR_MDCE | UART_MCR_FCM); + break; + + default: + break; + } + return value; +} + +static int ingenic_uart_probe(struct platform_device *pdev) +{ + struct uart_8250_port uart = {}; + struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + struct ingenic_uart_data *data; + const struct ingenic_uart_config *cdata; + const struct of_device_id *match; + int err, line; + + match = of_match_device(of_match, &pdev->dev); + if (!match) { + dev_err(&pdev->dev, "Error: No device match found\n"); + return -ENODEV; + } + cdata = match->data; + + if (!regs || !irq) { + dev_err(&pdev->dev, "no registers/irq defined\n"); + return -EINVAL; + } + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + spin_lock_init(&uart.port.lock); + uart.port.type = PORT_16550A; + uart.port.flags = UPF_SKIP_TEST | UPF_IOREMAP | UPF_FIXED_TYPE; + uart.port.iotype = UPIO_MEM; + uart.port.mapbase = regs->start; + uart.port.regshift = 2; + uart.port.serial_out = ingenic_uart_serial_out; + uart.port.serial_in = ingenic_uart_serial_in; + uart.port.irq = irq->start; + uart.port.dev = &pdev->dev; + uart.port.fifosize = cdata->fifosize; + uart.tx_loadsz = cdata->tx_loadsz; + uart.capabilities = UART_CAP_FIFO | UART_CAP_RTOIE; + + /* Check for a fixed line number */ + line = of_alias_get_id(pdev->dev.of_node, "serial"); + if (line >= 0) + uart.port.line = line; + + uart.port.membase = devm_ioremap(&pdev->dev, regs->start, + resource_size(regs)); + if (!uart.port.membase) + return -ENOMEM; + + data->clk_module = devm_clk_get(&pdev->dev, "module"); + if (IS_ERR(data->clk_module)) { + err = PTR_ERR(data->clk_module); + if (err != -EPROBE_DEFER) + dev_err(&pdev->dev, + "unable to get module clock: %d\n", err); + return err; + } + + data->clk_baud = devm_clk_get(&pdev->dev, "baud"); + if (IS_ERR(data->clk_baud)) { + err = PTR_ERR(data->clk_baud); + if (err != -EPROBE_DEFER) + dev_err(&pdev->dev, + "unable to get baud clock: %d\n", err); + return err; + } + + err = clk_prepare_enable(data->clk_module); + if (err) { + dev_err(&pdev->dev, "could not enable module clock: %d\n", err); + goto out; + } + + err = clk_prepare_enable(data->clk_baud); + if (err) { + dev_err(&pdev->dev, "could not enable baud clock: %d\n", err); + goto out_disable_moduleclk; + } + uart.port.uartclk = clk_get_rate(data->clk_baud); + + data->line = serial8250_register_8250_port(&uart); + if (data->line < 0) { + err = data->line; + goto out_disable_baudclk; + } + + platform_set_drvdata(pdev, data); + return 0; + +out_disable_baudclk: + clk_disable_unprepare(data->clk_baud); +out_disable_moduleclk: + clk_disable_unprepare(data->clk_module); +out: + return err; +} + +static int ingenic_uart_remove(struct platform_device *pdev) +{ + struct ingenic_uart_data *data = platform_get_drvdata(pdev); + + serial8250_unregister_port(data->line); + clk_disable_unprepare(data->clk_module); + clk_disable_unprepare(data->clk_baud); + return 0; +} + +static const struct ingenic_uart_config jz4740_uart_config = { + .tx_loadsz = 8, + .fifosize = 16, +}; + +static const struct ingenic_uart_config jz4760_uart_config = { + .tx_loadsz = 16, + .fifosize = 32, +}; + +static const struct ingenic_uart_config jz4780_uart_config = { + .tx_loadsz = 32, + .fifosize = 64, +}; + +static const struct of_device_id of_match[] = { + { .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config }, + { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config }, + { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config }, + { .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, of_match); + +static struct platform_driver ingenic_uart_platform_driver = { + .driver = { + .name = "ingenic-uart", + .of_match_table = of_match, + }, + .probe = ingenic_uart_probe, + .remove = ingenic_uart_remove, +}; + +module_platform_driver(ingenic_uart_platform_driver); + +MODULE_AUTHOR("Paul Burton"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Ingenic SoC UART driver"); diff --git a/kernel/drivers/tty/serial/8250/8250_lpc18xx.c b/kernel/drivers/tty/serial/8250/8250_lpc18xx.c new file mode 100644 index 000000000..99cd47885 --- /dev/null +++ b/kernel/drivers/tty/serial/8250/8250_lpc18xx.c @@ -0,0 +1,230 @@ +/* + * Serial port driver for NXP LPC18xx/43xx UART + * + * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> + * + * Based on 8250_mtk.c: + * Copyright (c) 2014 MundoReader S.L. + * Matthias Brugger <matthias.bgg@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include "8250.h" + +/* Additional LPC18xx/43xx 8250 registers and bits */ +#define LPC18XX_UART_RS485CTRL (0x04c / sizeof(u32)) +#define LPC18XX_UART_RS485CTRL_NMMEN BIT(0) +#define LPC18XX_UART_RS485CTRL_DCTRL BIT(4) +#define LPC18XX_UART_RS485CTRL_OINV BIT(5) +#define LPC18XX_UART_RS485DLY (0x054 / sizeof(u32)) +#define LPC18XX_UART_RS485DLY_MAX 255 + +struct lpc18xx_uart_data { + struct uart_8250_dma dma; + struct clk *clk_uart; + struct clk *clk_reg; + int line; +}; + +static int lpc18xx_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct uart_8250_port *up = up_to_u8250p(port); + u32 rs485_ctrl_reg = 0; + u32 rs485_dly_reg = 0; + unsigned baud_clk; + + if (rs485->flags & SER_RS485_ENABLED) + memset(rs485->padding, 0, sizeof(rs485->padding)); + else + memset(rs485, 0, sizeof(*rs485)); + + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND; + + if (rs485->flags & SER_RS485_ENABLED) { + rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_NMMEN | + LPC18XX_UART_RS485CTRL_DCTRL; + + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + rs485_ctrl_reg |= LPC18XX_UART_RS485CTRL_OINV; + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + } else { + rs485->flags |= SER_RS485_RTS_AFTER_SEND; + } + } + + if (rs485->delay_rts_after_send) { + baud_clk = port->uartclk / up->dl_read(up); + rs485_dly_reg = DIV_ROUND_UP(rs485->delay_rts_after_send + * baud_clk, MSEC_PER_SEC); + + if (rs485_dly_reg > LPC18XX_UART_RS485DLY_MAX) + rs485_dly_reg = LPC18XX_UART_RS485DLY_MAX; + + /* Calculate the resulting delay in ms */ + rs485->delay_rts_after_send = (rs485_dly_reg * MSEC_PER_SEC) + / baud_clk; + } + + /* Delay RTS before send not supported */ + rs485->delay_rts_before_send = 0; + + serial_out(up, LPC18XX_UART_RS485CTRL, rs485_ctrl_reg); + serial_out(up, LPC18XX_UART_RS485DLY, rs485_dly_reg); + + port->rs485 = *rs485; + + return 0; +} + +static void lpc18xx_uart_serial_out(struct uart_port *p, int offset, int value) +{ + /* + * For DMA mode one must ensure that the UART_FCR_DMA_SELECT + * bit is set when FIFO is enabled. Even if DMA is not used + * setting this bit doesn't seem to affect anything. + */ + if (offset == UART_FCR && (value & UART_FCR_ENABLE_FIFO)) + value |= UART_FCR_DMA_SELECT; + + offset = offset << p->regshift; + writel(value, p->membase + offset); +} + +static int lpc18xx_serial_probe(struct platform_device *pdev) +{ + struct lpc18xx_uart_data *data; + struct uart_8250_port uart; + struct resource *res; + int irq, ret; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "irq not found"); + return irq; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "memory resource not found"); + return -EINVAL; + } + + memset(&uart, 0, sizeof(uart)); + + uart.port.membase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!uart.port.membase) + return -ENOMEM; + + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->clk_uart = devm_clk_get(&pdev->dev, "uartclk"); + if (IS_ERR(data->clk_uart)) { + dev_err(&pdev->dev, "uart clock not found\n"); + return PTR_ERR(data->clk_uart); + } + + data->clk_reg = devm_clk_get(&pdev->dev, "reg"); + if (IS_ERR(data->clk_reg)) { + dev_err(&pdev->dev, "reg clock not found\n"); + return PTR_ERR(data->clk_reg); + } + + ret = clk_prepare_enable(data->clk_reg); + if (ret) { + dev_err(&pdev->dev, "unable to enable reg clock\n"); + return ret; + } + + ret = clk_prepare_enable(data->clk_uart); + if (ret) { + dev_err(&pdev->dev, "unable to enable uart clock\n"); + goto dis_clk_reg; + } + + ret = of_alias_get_id(pdev->dev.of_node, "serial"); + if (ret >= 0) + uart.port.line = ret; + + data->dma.rx_param = data; + data->dma.tx_param = data; + + spin_lock_init(&uart.port.lock); + uart.port.dev = &pdev->dev; + uart.port.irq = irq; + uart.port.iotype = UPIO_MEM32; + uart.port.mapbase = res->start; + uart.port.regshift = 2; + uart.port.type = PORT_16550A; + uart.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_SKIP_TEST; + uart.port.uartclk = clk_get_rate(data->clk_uart); + uart.port.private_data = data; + uart.port.rs485_config = lpc18xx_rs485_config; + uart.port.serial_out = lpc18xx_uart_serial_out; + + uart.dma = &data->dma; + uart.dma->rxconf.src_maxburst = 1; + uart.dma->txconf.dst_maxburst = 1; + + ret = serial8250_register_8250_port(&uart); + if (ret < 0) { + dev_err(&pdev->dev, "unable to register 8250 port\n"); + goto dis_uart_clk; + } + + data->line = ret; + platform_set_drvdata(pdev, data); + + return 0; + +dis_uart_clk: + clk_disable_unprepare(data->clk_uart); +dis_clk_reg: + clk_disable_unprepare(data->clk_reg); + return ret; +} + +static int lpc18xx_serial_remove(struct platform_device *pdev) +{ + struct lpc18xx_uart_data *data = platform_get_drvdata(pdev); + + serial8250_unregister_port(data->line); + clk_disable_unprepare(data->clk_uart); + clk_disable_unprepare(data->clk_reg); + + return 0; +} + +static const struct of_device_id lpc18xx_serial_match[] = { + { .compatible = "nxp,lpc1850-uart" }, + { }, +}; +MODULE_DEVICE_TABLE(of, lpc18xx_serial_match); + +static struct platform_driver lpc18xx_serial_driver = { + .probe = lpc18xx_serial_probe, + .remove = lpc18xx_serial_remove, + .driver = { + .name = "lpc18xx-uart", + .of_match_table = lpc18xx_serial_match, + }, +}; +module_platform_driver(lpc18xx_serial_driver); + +MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>"); +MODULE_DESCRIPTION("Serial port driver NXP LPC18xx/43xx devices"); +MODULE_LICENSE("GPL v2"); diff --git a/kernel/drivers/tty/serial/8250/8250_mid.c b/kernel/drivers/tty/serial/8250/8250_mid.c new file mode 100644 index 000000000..88531a36b --- /dev/null +++ b/kernel/drivers/tty/serial/8250/8250_mid.c @@ -0,0 +1,326 @@ +/* + * 8250_mid.c - Driver for UART on Intel Penwell and various other Intel SOCs + * + * Copyright (C) 2015 Intel Corporation + * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/rational.h> +#include <linux/module.h> +#include <linux/pci.h> + +#include <linux/dma/hsu.h> + +#include "8250.h" + +#define PCI_DEVICE_ID_INTEL_PNW_UART1 0x081b +#define PCI_DEVICE_ID_INTEL_PNW_UART2 0x081c +#define PCI_DEVICE_ID_INTEL_PNW_UART3 0x081d +#define PCI_DEVICE_ID_INTEL_TNG_UART 0x1191 +#define PCI_DEVICE_ID_INTEL_DNV_UART 0x19d8 + +/* Intel MID Specific registers */ +#define INTEL_MID_UART_PS 0x30 +#define INTEL_MID_UART_MUL 0x34 +#define INTEL_MID_UART_DIV 0x38 + +struct mid8250; + +struct mid8250_board { + unsigned long freq; + unsigned int base_baud; + int (*setup)(struct mid8250 *, struct uart_port *p); + void (*exit)(struct mid8250 *); +}; + +struct mid8250 { + int line; + int dma_index; + struct pci_dev *dma_dev; + struct uart_8250_dma dma; + struct mid8250_board *board; + struct hsu_dma_chip dma_chip; +}; + +/*****************************************************************************/ + +static int pnw_setup(struct mid8250 *mid, struct uart_port *p) +{ + struct pci_dev *pdev = to_pci_dev(p->dev); + + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_PNW_UART1: + mid->dma_index = 0; + break; + case PCI_DEVICE_ID_INTEL_PNW_UART2: + mid->dma_index = 1; + break; + case PCI_DEVICE_ID_INTEL_PNW_UART3: + mid->dma_index = 2; + break; + default: + return -EINVAL; + } + + mid->dma_dev = pci_get_slot(pdev->bus, + PCI_DEVFN(PCI_SLOT(pdev->devfn), 3)); + return 0; +} + +static int tng_setup(struct mid8250 *mid, struct uart_port *p) +{ + struct pci_dev *pdev = to_pci_dev(p->dev); + int index = PCI_FUNC(pdev->devfn); + + /* Currently no support for HSU port0 */ + if (index-- == 0) + return -ENODEV; + + mid->dma_index = index; + mid->dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(5, 0)); + return 0; +} + +static int dnv_handle_irq(struct uart_port *p) +{ + struct mid8250 *mid = p->private_data; + int ret; + + ret = hsu_dma_irq(&mid->dma_chip, 0); + ret |= hsu_dma_irq(&mid->dma_chip, 1); + + /* For now, letting the HW generate separate interrupt for the UART */ + if (ret) + return ret; + + return serial8250_handle_irq(p, serial_port_in(p, UART_IIR)); +} + +#define DNV_DMA_CHAN_OFFSET 0x80 + +static int dnv_setup(struct mid8250 *mid, struct uart_port *p) +{ + struct hsu_dma_chip *chip = &mid->dma_chip; + struct pci_dev *pdev = to_pci_dev(p->dev); + int ret; + + chip->dev = &pdev->dev; + chip->irq = pdev->irq; + chip->regs = p->membase; + chip->length = pci_resource_len(pdev, 0); + chip->offset = DNV_DMA_CHAN_OFFSET; + + /* Falling back to PIO mode if DMA probing fails */ + ret = hsu_dma_probe(chip); + if (ret) + return 0; + + mid->dma_dev = pdev; + + p->handle_irq = dnv_handle_irq; + return 0; +} + +static void dnv_exit(struct mid8250 *mid) +{ + if (!mid->dma_dev) + return; + hsu_dma_remove(&mid->dma_chip); +} + +/*****************************************************************************/ + +static void mid8250_set_termios(struct uart_port *p, + struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = tty_termios_baud_rate(termios); + struct mid8250 *mid = p->private_data; + unsigned short ps = 16; + unsigned long fuart = baud * ps; + unsigned long w = BIT(24) - 1; + unsigned long mul, div; + + if (mid->board->freq < fuart) { + /* Find prescaler value that satisfies Fuart < Fref */ + if (mid->board->freq > baud) + ps = mid->board->freq / baud; /* baud rate too high */ + else + ps = 1; /* PLL case */ + fuart = baud * ps; + } else { + /* Get Fuart closer to Fref */ + fuart *= rounddown_pow_of_two(mid->board->freq / fuart); + } + + rational_best_approximation(fuart, mid->board->freq, w, w, &mul, &div); + p->uartclk = fuart * 16 / ps; /* core uses ps = 16 always */ + + writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */ + writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */ + writel(div, p->membase + INTEL_MID_UART_DIV); + + serial8250_do_set_termios(p, termios, old); +} + +static bool mid8250_dma_filter(struct dma_chan *chan, void *param) +{ + struct hsu_dma_slave *s = param; + + if (s->dma_dev != chan->device->dev || s->chan_id != chan->chan_id) + return false; + + chan->private = s; + return true; +} + +static int mid8250_dma_setup(struct mid8250 *mid, struct uart_8250_port *port) +{ + struct uart_8250_dma *dma = &mid->dma; + struct device *dev = port->port.dev; + struct hsu_dma_slave *rx_param; + struct hsu_dma_slave *tx_param; + + if (!mid->dma_dev) + return 0; + + rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL); + if (!rx_param) + return -ENOMEM; + + tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL); + if (!tx_param) + return -ENOMEM; + + rx_param->chan_id = mid->dma_index * 2 + 1; + tx_param->chan_id = mid->dma_index * 2; + + dma->rxconf.src_maxburst = 64; + dma->txconf.dst_maxburst = 64; + + rx_param->dma_dev = &mid->dma_dev->dev; + tx_param->dma_dev = &mid->dma_dev->dev; + + dma->fn = mid8250_dma_filter; + dma->rx_param = rx_param; + dma->tx_param = tx_param; + + port->dma = dma; + return 0; +} + +static int mid8250_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct uart_8250_port uart; + struct mid8250 *mid; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + pci_set_master(pdev); + + mid = devm_kzalloc(&pdev->dev, sizeof(*mid), GFP_KERNEL); + if (!mid) + return -ENOMEM; + + mid->board = (struct mid8250_board *)id->driver_data; + + memset(&uart, 0, sizeof(struct uart_8250_port)); + + uart.port.dev = &pdev->dev; + uart.port.irq = pdev->irq; + uart.port.private_data = mid; + uart.port.type = PORT_16750; + uart.port.iotype = UPIO_MEM; + uart.port.uartclk = mid->board->base_baud * 16; + uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE; + uart.port.set_termios = mid8250_set_termios; + + uart.port.mapbase = pci_resource_start(pdev, 0); + uart.port.membase = pcim_iomap(pdev, 0, 0); + if (!uart.port.membase) + return -ENOMEM; + + if (mid->board->setup) { + ret = mid->board->setup(mid, &uart.port); + if (ret) + return ret; + } + + ret = mid8250_dma_setup(mid, &uart); + if (ret) + goto err; + + ret = serial8250_register_8250_port(&uart); + if (ret < 0) + goto err; + + mid->line = ret; + + pci_set_drvdata(pdev, mid); + return 0; +err: + if (mid->board->exit) + mid->board->exit(mid); + return ret; +} + +static void mid8250_remove(struct pci_dev *pdev) +{ + struct mid8250 *mid = pci_get_drvdata(pdev); + + if (mid->board->exit) + mid->board->exit(mid); + + serial8250_unregister_port(mid->line); +} + +static const struct mid8250_board pnw_board = { + .freq = 50000000, + .base_baud = 115200, + .setup = pnw_setup, +}; + +static const struct mid8250_board tng_board = { + .freq = 38400000, + .base_baud = 1843200, + .setup = tng_setup, +}; + +static const struct mid8250_board dnv_board = { + .freq = 133333333, + .base_baud = 115200, + .setup = dnv_setup, + .exit = dnv_exit, +}; + +#define MID_DEVICE(id, board) { PCI_VDEVICE(INTEL, id), (kernel_ulong_t)&board } + +static const struct pci_device_id pci_ids[] = { + MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART1, pnw_board), + MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART2, pnw_board), + MID_DEVICE(PCI_DEVICE_ID_INTEL_PNW_UART3, pnw_board), + MID_DEVICE(PCI_DEVICE_ID_INTEL_TNG_UART, tng_board), + MID_DEVICE(PCI_DEVICE_ID_INTEL_DNV_UART, dnv_board), + { }, +}; +MODULE_DEVICE_TABLE(pci, pci_ids); + +static struct pci_driver mid8250_pci_driver = { + .name = "8250_mid", + .id_table = pci_ids, + .probe = mid8250_probe, + .remove = mid8250_remove, +}; + +module_pci_driver(mid8250_pci_driver); + +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel MID UART driver"); diff --git a/kernel/drivers/tty/serial/8250/8250_mtk.c b/kernel/drivers/tty/serial/8250/8250_mtk.c index 7a11fac77..78883ca64 100644 --- a/kernel/drivers/tty/serial/8250/8250_mtk.c +++ b/kernel/drivers/tty/serial/8250/8250_mtk.c @@ -34,6 +34,7 @@ struct mtk8250_data { int line; struct clk *uart_clk; + struct clk *bus_clk; }; static void @@ -115,6 +116,36 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, tty_termios_encode_baud_rate(termios, baud, baud); } +static int mtk8250_runtime_suspend(struct device *dev) +{ + struct mtk8250_data *data = dev_get_drvdata(dev); + + clk_disable_unprepare(data->uart_clk); + clk_disable_unprepare(data->bus_clk); + + return 0; +} + +static int mtk8250_runtime_resume(struct device *dev) +{ + struct mtk8250_data *data = dev_get_drvdata(dev); + int err; + + err = clk_prepare_enable(data->uart_clk); + if (err) { + dev_warn(dev, "Can't enable clock\n"); + return err; + } + + err = clk_prepare_enable(data->bus_clk); + if (err) { + dev_warn(dev, "Can't enable bus clock\n"); + return err; + } + + return 0; +} + static void mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) { @@ -130,22 +161,24 @@ mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p, struct mtk8250_data *data) { - int err; - struct device_node *np = pdev->dev.of_node; - - data->uart_clk = of_clk_get(np, 0); + data->uart_clk = devm_clk_get(&pdev->dev, "baud"); if (IS_ERR(data->uart_clk)) { - dev_warn(&pdev->dev, "Can't get timer clock\n"); - return PTR_ERR(data->uart_clk); + /* + * For compatibility with older device trees try unnamed + * clk when no baud clk can be found. + */ + data->uart_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(data->uart_clk)) { + dev_warn(&pdev->dev, "Can't get uart clock\n"); + return PTR_ERR(data->uart_clk); + } + + return 0; } - err = clk_prepare_enable(data->uart_clk); - if (err) { - dev_warn(&pdev->dev, "Can't prepare clock\n"); - clk_put(data->uart_clk); - return err; - } - p->uartclk = clk_get_rate(data->uart_clk); + data->bus_clk = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(data->bus_clk)) + return PTR_ERR(data->bus_clk); return 0; } @@ -190,19 +223,24 @@ static int mtk8250_probe(struct platform_device *pdev) uart.port.regshift = 2; uart.port.private_data = data; uart.port.set_termios = mtk8250_set_termios; + uart.port.uartclk = clk_get_rate(data->uart_clk); /* Disable Rate Fix function */ writel(0x0, uart.port.membase + (MTK_UART_RATE_FIX << uart.port.regshift)); - data->line = serial8250_register_8250_port(&uart); - if (data->line < 0) - return data->line; - platform_set_drvdata(pdev, data); - pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + err = mtk8250_runtime_resume(&pdev->dev); + if (err) + return err; + } + + data->line = serial8250_register_8250_port(&uart); + if (data->line < 0) + return data->line; return 0; } @@ -214,13 +252,13 @@ static int mtk8250_remove(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); serial8250_unregister_port(data->line); - if (!IS_ERR(data->uart_clk)) { - clk_disable_unprepare(data->uart_clk); - clk_put(data->uart_clk); - } pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); + + if (!pm_runtime_status_suspended(&pdev->dev)) + mtk8250_runtime_suspend(&pdev->dev); + return 0; } @@ -244,28 +282,6 @@ static int mtk8250_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -#ifdef CONFIG_PM -static int mtk8250_runtime_suspend(struct device *dev) -{ - struct mtk8250_data *data = dev_get_drvdata(dev); - - if (!IS_ERR(data->uart_clk)) - clk_disable_unprepare(data->uart_clk); - - return 0; -} - -static int mtk8250_runtime_resume(struct device *dev) -{ - struct mtk8250_data *data = dev_get_drvdata(dev); - - if (!IS_ERR(data->uart_clk)) - clk_prepare_enable(data->uart_clk); - - return 0; -} -#endif - static const struct dev_pm_ops mtk8250_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mtk8250_suspend, mtk8250_resume) SET_RUNTIME_PM_OPS(mtk8250_runtime_suspend, mtk8250_runtime_resume, @@ -289,6 +305,21 @@ static struct platform_driver mtk8250_platform_driver = { }; module_platform_driver(mtk8250_platform_driver); +#ifdef CONFIG_SERIAL_8250_CONSOLE +static int __init early_mtk8250_setup(struct earlycon_device *device, + const char *options) +{ + if (!device->port.membase) + return -ENODEV; + + device->port.iotype = UPIO_MEM32; + + return early_serial8250_setup(device, NULL); +} + +OF_EARLYCON_DECLARE(mtk8250, "mediatek,mt6577-uart", early_mtk8250_setup); +#endif + MODULE_AUTHOR("Matthias Brugger"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Mediatek 8250 serial port driver"); diff --git a/kernel/drivers/tty/serial/8250/8250_omap.c b/kernel/drivers/tty/serial/8250/8250_omap.c index dce1a2370..a2c0734c7 100644 --- a/kernel/drivers/tty/serial/8250/8250_omap.c +++ b/kernel/drivers/tty/serial/8250/8250_omap.c @@ -16,12 +16,14 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/of_gpio.h> #include <linux/of_irq.h> #include <linux/delay.h> #include <linux/pm_runtime.h> #include <linux/console.h> #include <linux/pm_qos.h> +#include <linux/pm_wakeirq.h> #include <linux/dma-mapping.h> #include "8250.h" @@ -31,6 +33,11 @@ #define UART_ERRATA_i202_MDR1_ACCESS (1 << 0) #define OMAP_UART_WER_HAS_TX_WAKEUP (1 << 1) #define OMAP_DMA_TX_KICK (1 << 2) +/* + * See Advisory 21 in AM437x errata SPRZ408B, updated April 2015. + * The same errata is applicable to AM335x and DRA7x processors too. + */ +#define UART_ERRATA_CLOCK_DISABLE (1 << 3) #define OMAP_UART_FCR_RX_TRIG 6 #define OMAP_UART_FCR_TX_TRIG 4 @@ -52,6 +59,12 @@ #define OMAP_UART_MVR_MAJ_SHIFT 8 #define OMAP_UART_MVR_MIN_MASK 0x3f +/* SYSC register bitmasks */ +#define OMAP_UART_SYSC_SOFTRESET (1 << 1) + +/* SYSS register bitmasks */ +#define OMAP_UART_SYSS_RESETDONE (1 << 0) + #define UART_TI752_TLR_TX 0 #define UART_TI752_TLR_RX 4 @@ -98,6 +111,8 @@ struct omap8250_priv { struct pm_qos_request pm_qos_request; struct work_struct qos_work; struct uart_8250_dma omap8250_dma; + spinlock_t rx_dma_lock; + bool rx_dma_broken; }; static u32 uart_read(struct uart_8250_port *up, u32 reg) @@ -230,6 +245,15 @@ static void omap8250_update_scr(struct uart_8250_port *up, serial_out(up, UART_OMAP_SCR, priv->scr); } +static void omap8250_update_mdr1(struct uart_8250_port *up, + struct omap8250_priv *priv) +{ + if (priv->habit & UART_ERRATA_i202_MDR1_ACCESS) + omap_8250_mdr1_errataset(up, priv); + else + serial_out(up, UART_OMAP_MDR1, priv->mdr1); +} + static void omap8250_restore_regs(struct uart_8250_port *up) { struct omap8250_priv *priv = up->port.private_data; @@ -280,11 +304,9 @@ static void omap8250_restore_regs(struct uart_8250_port *up) serial_out(up, UART_XOFF1, priv->xoff); serial_out(up, UART_LCR, up->lcr); - /* need mode A for FCR */ - if (priv->habit & UART_ERRATA_i202_MDR1_ACCESS) - omap_8250_mdr1_errataset(up, priv); - else - serial_out(up, UART_OMAP_MDR1, priv->mdr1); + + omap8250_update_mdr1(up, priv); + up->port.ops->set_mctrl(&up->port, up->port.mctrl); } @@ -417,7 +439,6 @@ static void omap_8250_set_termios(struct uart_port *port, priv->xoff = termios->c_cc[VSTOP]; priv->efr = 0; - up->mcr &= ~(UART_MCR_RTS | UART_MCR_XONANY); up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF); if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) { @@ -426,12 +447,9 @@ static void omap_8250_set_termios(struct uart_port *port, priv->efr |= UART_EFR_CTS; } else if (up->port.flags & UPF_SOFT_FLOW) { /* - * IXON Flag: - * Enable XON/XOFF flow control on input. - * Receiver compares XON1, XOFF1. + * OMAP rx s/w flow control is borked; the transmitter remains + * stuck off even if rx flow control is subsequently disabled */ - if (termios->c_iflag & IXON) - priv->efr |= OMAP_UART_SW_RX; /* * IXOFF Flag: @@ -442,15 +460,6 @@ static void omap_8250_set_termios(struct uart_port *port, up->port.status |= UPSTAT_AUTOXOFF; priv->efr |= OMAP_UART_SW_TX; } - - /* - * IXANY Flag: - * Enable any character to restart output. - * Operation resumes after receiving any - * character after recognition of the XOFF character - */ - if (termios->c_iflag & IXANY) - up->mcr |= UART_MCR_XONANY; } omap8250_restore_regs(up); @@ -528,14 +537,14 @@ static void omap_serial_fill_features_erratas(struct uart_8250_port *up, switch (revision) { case OMAP_UART_REV_46: - priv->habit = UART_ERRATA_i202_MDR1_ACCESS; + priv->habit |= UART_ERRATA_i202_MDR1_ACCESS; break; case OMAP_UART_REV_52: - priv->habit = UART_ERRATA_i202_MDR1_ACCESS | + priv->habit |= UART_ERRATA_i202_MDR1_ACCESS | OMAP_UART_WER_HAS_TX_WAKEUP; break; case OMAP_UART_REV_63: - priv->habit = UART_ERRATA_i202_MDR1_ACCESS | + priv->habit |= UART_ERRATA_i202_MDR1_ACCESS | OMAP_UART_WER_HAS_TX_WAKEUP; break; default: @@ -551,17 +560,6 @@ static void omap8250_uart_qos_work(struct work_struct *work) pm_qos_update_request(&priv->pm_qos_request, priv->latency); } -static irqreturn_t omap_wake_irq(int irq, void *dev_id) -{ - struct uart_port *port = dev_id; - int ret; - - ret = port->handle_irq(port); - if (ret) - return IRQ_HANDLED; - return IRQ_NONE; -} - #ifdef CONFIG_SERIAL_8250_DMA static int omap_8250_dma_handle_irq(struct uart_port *port); #endif @@ -595,11 +593,9 @@ static int omap_8250_startup(struct uart_port *port) int ret; if (priv->wakeirq) { - ret = request_irq(priv->wakeirq, omap_wake_irq, - port->irqflags, "uart wakeup irq", port); + ret = dev_pm_set_dedicated_wake_irq(port->dev, priv->wakeirq); if (ret) return ret; - disable_irq(priv->wakeirq); } pm_runtime_get_sync(port->dev); @@ -648,8 +644,7 @@ static int omap_8250_startup(struct uart_port *port) err: pm_runtime_mark_last_busy(port->dev); pm_runtime_put_autosuspend(port->dev); - if (priv->wakeirq) - free_irq(priv->wakeirq, port); + dev_pm_clear_wake_irq(port->dev); return ret; } @@ -681,10 +676,8 @@ static void omap_8250_shutdown(struct uart_port *port) pm_runtime_mark_last_busy(port->dev); pm_runtime_put_autosuspend(port->dev); - free_irq(port->irq, port); - if (priv->wakeirq) - free_irq(priv->wakeirq, port); + dev_pm_clear_wake_irq(port->dev); } static void omap_8250_throttle(struct uart_port *port) @@ -726,22 +719,35 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir); static void __dma_rx_do_complete(struct uart_8250_port *p, bool error) { + struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; struct tty_port *tty_port = &p->port.state->port; struct dma_tx_state state; int count; + unsigned long flags; + int ret; dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr, dma->rx_size, DMA_FROM_DEVICE); + spin_lock_irqsave(&priv->rx_dma_lock, flags); + + if (!dma->rx_running) + goto unlock; + dma->rx_running = 0; dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); dmaengine_terminate_all(dma->rxchan); count = dma->rx_size - state.residue; - tty_insert_flip_string(tty_port, dma->rx_buf, count); - p->port.icount.rx += count; + ret = tty_insert_flip_string(tty_port, dma->rx_buf, count); + + p->port.icount.rx += ret; + p->port.icount.buf_overrun += count - ret; +unlock: + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); + if (!error) omap_8250_rx_dma(p, 0); @@ -753,28 +759,48 @@ static void __dma_rx_complete(void *param) __dma_rx_do_complete(param, false); } +static void omap_8250_rx_dma_flush(struct uart_8250_port *p) +{ + struct omap8250_priv *priv = p->port.private_data; + struct uart_8250_dma *dma = p->dma; + unsigned long flags; + int ret; + + spin_lock_irqsave(&priv->rx_dma_lock, flags); + + if (!dma->rx_running) { + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); + return; + } + + ret = dmaengine_pause(dma->rxchan); + if (WARN_ON_ONCE(ret)) + priv->rx_dma_broken = true; + + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); + + __dma_rx_do_complete(p, true); +} + static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) { + struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; + int err = 0; struct dma_async_tx_descriptor *desc; + unsigned long flags; switch (iir & 0x3f) { case UART_IIR_RLSI: /* 8250_core handles errors and break interrupts */ - if (dma->rx_running) { - dmaengine_pause(dma->rxchan); - __dma_rx_do_complete(p, true); - } + omap_8250_rx_dma_flush(p); return -EIO; case UART_IIR_RX_TIMEOUT: /* * If RCVR FIFO trigger level was not reached, complete the * transfer and let 8250_core copy the remaining data. */ - if (dma->rx_running) { - dmaengine_pause(dma->rxchan); - __dma_rx_do_complete(p, true); - } + omap_8250_rx_dma_flush(p); return -ETIMEDOUT; case UART_IIR_RDI: /* @@ -786,24 +812,28 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) * the DMA won't do anything soon so we have to cancel the DMA * transfer and purge the FIFO manually. */ - if (dma->rx_running) { - dmaengine_pause(dma->rxchan); - __dma_rx_do_complete(p, true); - } + omap_8250_rx_dma_flush(p); return -ETIMEDOUT; default: break; } + if (priv->rx_dma_broken) + return -EINVAL; + + spin_lock_irqsave(&priv->rx_dma_lock, flags); + if (dma->rx_running) - return 0; + goto out; desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) - return -EBUSY; + if (!desc) { + err = -EBUSY; + goto out; + } dma->rx_running = 1; desc->callback = __dma_rx_complete; @@ -815,7 +845,9 @@ static int omap_8250_rx_dma(struct uart_8250_port *p, unsigned int iir) dma->rx_size, DMA_FROM_DEVICE); dma_async_issue_pending(dma->rxchan); - return 0; +out: + spin_unlock_irqrestore(&priv->rx_dma_lock, flags); + return err; } static int omap_8250_tx_dma(struct uart_8250_port *p); @@ -1038,6 +1070,20 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } +static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE; +static const u8 am4372_habit = UART_ERRATA_CLOCK_DISABLE; + +static const struct of_device_id omap8250_dt_ids[] = { + { .compatible = "ti,omap2-uart" }, + { .compatible = "ti,omap3-uart" }, + { .compatible = "ti,omap4-uart" }, + { .compatible = "ti,am3352-uart", .data = &am3352_habit, }, + { .compatible = "ti,am4372-uart", .data = &am4372_habit, }, + { .compatible = "ti,dra742-uart", .data = &am4372_habit, }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap8250_dt_ids); + static int omap8250_probe(struct platform_device *pdev) { struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1102,11 +1148,17 @@ static int omap8250_probe(struct platform_device *pdev) up.port.unthrottle = omap_8250_unthrottle; if (pdev->dev.of_node) { + const struct of_device_id *id; + ret = of_alias_get_id(pdev->dev.of_node, "serial"); of_property_read_u32(pdev->dev.of_node, "clock-frequency", &up.port.uartclk); priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1); + + id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev); + if (id && id->data) + priv->habit |= *(u8 *)id->data; } else { ret = pdev->id; } @@ -1129,6 +1181,8 @@ static int omap8250_probe(struct platform_device *pdev) priv->latency); INIT_WORK(&priv->qos_work, omap8250_uart_qos_work); + spin_lock_init(&priv->rx_dma_lock); + device_init_wakeup(&pdev->dev, true); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, -1); @@ -1162,6 +1216,11 @@ static int omap8250_probe(struct platform_device *pdev) if (of_machine_is_compatible("ti,am33xx")) priv->habit |= OMAP_DMA_TX_KICK; + /* + * pause is currently not supported atleast on omap-sdma + * and edma on most earlier kernels. + */ + priv->rx_dma_broken = true; } } #endif @@ -1193,31 +1252,6 @@ static int omap8250_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM - -static inline void omap8250_enable_wakeirq(struct omap8250_priv *priv, - bool enable) -{ - if (!priv->wakeirq) - return; - - if (enable) - enable_irq(priv->wakeirq); - else - disable_irq_nosync(priv->wakeirq); -} - -static void omap8250_enable_wakeup(struct omap8250_priv *priv, - bool enable) -{ - if (enable == priv->wakeups_enabled) - return; - - omap8250_enable_wakeirq(priv, enable); - priv->wakeups_enabled = enable; -} -#endif - #ifdef CONFIG_PM_SLEEP static int omap8250_prepare(struct device *dev) { @@ -1244,11 +1278,6 @@ static int omap8250_suspend(struct device *dev) serial8250_suspend_port(priv->line); flush_work(&priv->qos_work); - - if (device_may_wakeup(dev)) - omap8250_enable_wakeup(priv, true); - else - omap8250_enable_wakeup(priv, false); return 0; } @@ -1256,9 +1285,6 @@ static int omap8250_resume(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); - if (device_may_wakeup(dev)) - omap8250_enable_wakeup(priv, false); - serial8250_resume_port(priv->line); return 0; } @@ -1272,17 +1298,46 @@ static int omap8250_lost_context(struct uart_8250_port *up) { u32 val; - val = serial_in(up, UART_OMAP_MDR1); + val = serial_in(up, UART_OMAP_SCR); /* - * If we lose context, then MDR1 is set to its reset value which is - * UART_OMAP_MDR1_DISABLE. After set_termios() we set it either to 13x - * or 16x but never to disable again. + * If we lose context, then SCR is set to its reset value of zero. + * After set_termios() we set bit 3 of SCR (TX_EMPTY_CTL_IT) to 1, + * among other bits, to never set the register back to zero again. */ - if (val == UART_OMAP_MDR1_DISABLE) + if (!val) return 1; return 0; } +/* TODO: in future, this should happen via API in drivers/reset/ */ +static int omap8250_soft_reset(struct device *dev) +{ + struct omap8250_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up = serial8250_get_port(priv->line); + int timeout = 100; + int sysc; + int syss; + + sysc = serial_in(up, UART_OMAP_SYSC); + + /* softreset the UART */ + sysc |= OMAP_UART_SYSC_SOFTRESET; + serial_out(up, UART_OMAP_SYSC, sysc); + + /* By experiments, 1us enough for reset complete on AM335x */ + do { + udelay(1); + syss = serial_in(up, UART_OMAP_SYSS); + } while (--timeout && !(syss & OMAP_UART_SYSS_RESETDONE)); + + if (!timeout) { + dev_err(dev, "timed out waiting for reset done\n"); + return -ETIMEDOUT; + } + + return 0; +} + static int omap8250_runtime_suspend(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); @@ -1300,8 +1355,18 @@ static int omap8250_runtime_suspend(struct device *dev) return -EBUSY; } - omap8250_enable_wakeup(priv, true); - if (up->dma) + if (priv->habit & UART_ERRATA_CLOCK_DISABLE) { + int ret; + + ret = omap8250_soft_reset(dev); + if (ret) + return ret; + + /* Restore to UART mode after reset (for wakeup) */ + omap8250_update_mdr1(up, priv); + } + + if (up->dma && up->dma->rxchan) omap_8250_rx_dma(up, UART_IIR_RX_TIMEOUT); priv->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; @@ -1321,13 +1386,12 @@ static int omap8250_runtime_resume(struct device *dev) return 0; up = serial8250_get_port(priv->line); - omap8250_enable_wakeup(priv, false); loss_cntx = omap8250_lost_context(up); if (loss_cntx) omap8250_restore_regs(up); - if (up->dma) + if (up->dma && up->dma->rxchan) omap_8250_rx_dma(up, 0); priv->latency = priv->calc_latency; @@ -1384,14 +1448,6 @@ static const struct dev_pm_ops omap8250_dev_pm_ops = { .complete = omap8250_complete, }; -static const struct of_device_id omap8250_dt_ids[] = { - { .compatible = "ti,omap2-uart" }, - { .compatible = "ti,omap3-uart" }, - { .compatible = "ti,omap4-uart" }, - {}, -}; -MODULE_DEVICE_TABLE(of, omap8250_dt_ids); - static struct platform_driver omap8250_platform_driver = { .driver = { .name = "omap8250", diff --git a/kernel/drivers/tty/serial/8250/8250_pci.c b/kernel/drivers/tty/serial/8250/8250_pci.c index 9373cca12..7cd6f9a90 100644 --- a/kernel/drivers/tty/serial/8250/8250_pci.c +++ b/kernel/drivers/tty/serial/8250/8250_pci.c @@ -28,7 +28,6 @@ #include <linux/dmaengine.h> #include <linux/platform_data/dma-dw.h> -#include <linux/platform_data/dma-hsu.h> #include "8250.h" @@ -1380,6 +1379,9 @@ ce4100_serial_setup(struct serial_private *priv, #define PCI_DEVICE_ID_INTEL_BSW_UART1 0x228a #define PCI_DEVICE_ID_INTEL_BSW_UART2 0x228c +#define PCI_DEVICE_ID_INTEL_BDW_UART1 0x9ce3 +#define PCI_DEVICE_ID_INTEL_BDW_UART2 0x9ce4 + #define BYT_PRV_CLK 0x800 #define BYT_PRV_CLK_EN (1 << 0) #define BYT_PRV_CLK_M_VAL_SHIFT 1 @@ -1417,6 +1419,10 @@ byt_set_termios(struct uart_port *p, struct ktermios *termios, reg |= BYT_PRV_CLK_EN | BYT_PRV_CLK_UPDATE; writel(reg, p->membase + BYT_PRV_CLK); + p->status &= ~UPSTAT_AUTOCTS; + if (termios->c_cflag & CRTSCTS) + p->status |= UPSTAT_AUTOCTS; + serial8250_do_set_termios(p, termios, old); } @@ -1458,11 +1464,13 @@ byt_serial_setup(struct serial_private *priv, switch (pdev->device) { case PCI_DEVICE_ID_INTEL_BYT_UART1: case PCI_DEVICE_ID_INTEL_BSW_UART1: + case PCI_DEVICE_ID_INTEL_BDW_UART1: rx_param->src_id = 3; tx_param->dst_id = 2; break; case PCI_DEVICE_ID_INTEL_BYT_UART2: case PCI_DEVICE_ID_INTEL_BSW_UART2: + case PCI_DEVICE_ID_INTEL_BDW_UART2: rx_param->src_id = 5; tx_param->dst_id = 4; break; @@ -1504,185 +1512,77 @@ byt_serial_setup(struct serial_private *priv, return ret; } -#define INTEL_MID_UART_PS 0x30 -#define INTEL_MID_UART_MUL 0x34 -#define INTEL_MID_UART_DIV 0x38 - -static void intel_mid_set_termios(struct uart_port *p, - struct ktermios *termios, - struct ktermios *old, - unsigned long fref) +static int +pci_omegapci_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) { - unsigned int baud = tty_termios_baud_rate(termios); - unsigned short ps = 16; - unsigned long fuart = baud * ps; - unsigned long w = BIT(24) - 1; - unsigned long mul, div; - - if (fref < fuart) { - /* Find prescaler value that satisfies Fuart < Fref */ - if (fref > baud) - ps = fref / baud; /* baud rate too high */ - else - ps = 1; /* PLL case */ - fuart = baud * ps; - } else { - /* Get Fuart closer to Fref */ - fuart *= rounddown_pow_of_two(fref / fuart); - } - - rational_best_approximation(fuart, fref, w, w, &mul, &div); - p->uartclk = fuart * 16 / ps; /* core uses ps = 16 always */ - - writel(ps, p->membase + INTEL_MID_UART_PS); /* set PS */ - writel(mul, p->membase + INTEL_MID_UART_MUL); /* set MUL */ - writel(div, p->membase + INTEL_MID_UART_DIV); - - serial8250_do_set_termios(p, termios, old); + return setup_port(priv, port, 2, idx * 8, 0); } -static void intel_mid_set_termios_38_4M(struct uart_port *p, - struct ktermios *termios, - struct ktermios *old) +static int +pci_brcm_trumanage_setup(struct serial_private *priv, + const struct pciserial_board *board, + struct uart_8250_port *port, int idx) { - intel_mid_set_termios(p, termios, old, 38400000); -} + int ret = pci_default_setup(priv, board, port, idx); -static void intel_mid_set_termios_50M(struct uart_port *p, - struct ktermios *termios, - struct ktermios *old) -{ - /* - * The uart clk is 50Mhz, and the baud rate come from: - * baud = 50M * MUL / (DIV * PS * DLAB) - */ - intel_mid_set_termios(p, termios, old, 50000000); + port->port.type = PORT_BRCM_TRUMANAGE; + port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); + return ret; } -static bool intel_mid_dma_filter(struct dma_chan *chan, void *param) -{ - struct hsu_dma_slave *s = param; - - if (s->dma_dev != chan->device->dev || s->chan_id != chan->chan_id) - return false; - - chan->private = s; - return true; -} +/* RTS will control by MCR if this bit is 0 */ +#define FINTEK_RTS_CONTROL_BY_HW BIT(4) +/* only worked with FINTEK_RTS_CONTROL_BY_HW on */ +#define FINTEK_RTS_INVERT BIT(5) -static int intel_mid_serial_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx, - int index, struct pci_dev *dma_dev) +/* We should do proper H/W transceiver setting before change to RS485 mode */ +static int pci_fintek_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485) { - struct device *dev = port->port.dev; - struct uart_8250_dma *dma; - struct hsu_dma_slave *tx_param, *rx_param; - - dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); - if (!dma) - return -ENOMEM; - - tx_param = devm_kzalloc(dev, sizeof(*tx_param), GFP_KERNEL); - if (!tx_param) - return -ENOMEM; + u8 setting; + u8 *index = (u8 *) port->private_data; + struct pci_dev *pci_dev = container_of(port->dev, struct pci_dev, + dev); - rx_param = devm_kzalloc(dev, sizeof(*rx_param), GFP_KERNEL); - if (!rx_param) - return -ENOMEM; + pci_read_config_byte(pci_dev, 0x40 + 8 * *index + 7, &setting); - rx_param->chan_id = index * 2 + 1; - tx_param->chan_id = index * 2; - - dma->rxconf.src_maxburst = 64; - dma->txconf.dst_maxburst = 64; - - rx_param->dma_dev = &dma_dev->dev; - tx_param->dma_dev = &dma_dev->dev; - - dma->fn = intel_mid_dma_filter; - dma->rx_param = rx_param; - dma->tx_param = tx_param; - - port->port.type = PORT_16750; - port->port.flags |= UPF_FIXED_PORT | UPF_FIXED_TYPE; - port->dma = dma; + if (!rs485) + rs485 = &port->rs485; + else if (rs485->flags & SER_RS485_ENABLED) + memset(rs485->padding, 0, sizeof(rs485->padding)); + else + memset(rs485, 0, sizeof(*rs485)); - return pci_default_setup(priv, board, port, idx); -} + /* F81504/508/512 not support RTS delay before or after send */ + rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; -#define PCI_DEVICE_ID_INTEL_PNW_UART1 0x081b -#define PCI_DEVICE_ID_INTEL_PNW_UART2 0x081c -#define PCI_DEVICE_ID_INTEL_PNW_UART3 0x081d + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable RTS H/W control mode */ + setting |= FINTEK_RTS_CONTROL_BY_HW; -static int pnw_serial_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - struct pci_dev *pdev = priv->dev; - struct pci_dev *dma_dev; - int index; + if (rs485->flags & SER_RS485_RTS_ON_SEND) { + /* RTS driving high on TX */ + setting &= ~FINTEK_RTS_INVERT; + } else { + /* RTS driving low on TX */ + setting |= FINTEK_RTS_INVERT; + } - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_PNW_UART1: - index = 0; - break; - case PCI_DEVICE_ID_INTEL_PNW_UART2: - index = 1; - break; - case PCI_DEVICE_ID_INTEL_PNW_UART3: - index = 2; - break; - default: - return -EINVAL; + rs485->delay_rts_after_send = 0; + rs485->delay_rts_before_send = 0; + } else { + /* Disable RTS H/W control mode */ + setting &= ~(FINTEK_RTS_CONTROL_BY_HW | FINTEK_RTS_INVERT); } - dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 3)); - - port->port.set_termios = intel_mid_set_termios_50M; + pci_write_config_byte(pci_dev, 0x40 + 8 * *index + 7, setting); - return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev); -} - -#define PCI_DEVICE_ID_INTEL_TNG_UART 0x1191 - -static int tng_serial_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - struct pci_dev *pdev = priv->dev; - struct pci_dev *dma_dev; - int index = PCI_FUNC(pdev->devfn); - - /* Currently no support for HSU port0 */ - if (index-- == 0) - return -ENODEV; - - dma_dev = pci_get_slot(pdev->bus, PCI_DEVFN(5, 0)); - - port->port.set_termios = intel_mid_set_termios_38_4M; + if (rs485 != &port->rs485) + port->rs485 = *rs485; - return intel_mid_serial_setup(priv, board, port, idx, index, dma_dev); -} - -static int -pci_omegapci_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - return setup_port(priv, port, 2, idx * 8, 0); -} - -static int -pci_brcm_trumanage_setup(struct serial_private *priv, - const struct pciserial_board *board, - struct uart_8250_port *port, int idx) -{ - int ret = pci_default_setup(priv, board, port, idx); - - port->port.type = PORT_BRCM_TRUMANAGE; - port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE); - return ret; + return 0; } static int pci_fintek_setup(struct serial_private *priv, @@ -1690,6 +1590,7 @@ static int pci_fintek_setup(struct serial_private *priv, struct uart_8250_port *port, int idx) { struct pci_dev *pdev = priv->dev; + u8 *data; u8 config_base; u16 iobase; @@ -1702,6 +1603,15 @@ static int pci_fintek_setup(struct serial_private *priv, port->port.iotype = UPIO_PORT; port->port.iobase = iobase; + port->port.rs485_config = pci_fintek_rs485_config; + + data = devm_kzalloc(&pdev->dev, sizeof(u8), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* preserve index in PCI configuration space */ + *data = idx; + port->port.private_data = data; return 0; } @@ -1712,6 +1622,8 @@ static int pci_fintek_init(struct pci_dev *dev) u32 max_port, i; u32 bar_data[3]; u8 config_base; + struct serial_private *priv = pci_get_drvdata(dev); + struct uart_8250_port *port; switch (dev->device) { case 0x1104: /* 4 ports */ @@ -1752,6 +1664,19 @@ static int pci_fintek_init(struct pci_dev *dev) (u8)((iobase & 0xff00) >> 8)); pci_write_config_byte(dev, config_base + 0x06, dev->irq); + + if (priv) { + /* re-apply RS232/485 mode when + * pciserial_resume_ports() + */ + port = serial8250_get_port(priv->line[i]); + pci_fintek_rs485_config(&port->port, NULL); + } else { + /* First init without port data + * force init to RS232 Mode + */ + pci_write_config_byte(dev, config_base + 0x07, 0x01); + } } return max_port; @@ -1823,6 +1748,9 @@ static int pci_eg20t_init(struct pci_dev *dev) #endif } +#define PCI_DEVICE_ID_EXAR_XR17V4358 0x4358 +#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 + static int pci_xr17c154_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1832,6 +1760,15 @@ pci_xr17c154_setup(struct serial_private *priv, return pci_default_setup(priv, board, port, idx); } +static inline int +xr17v35x_has_slave(struct serial_private *priv) +{ + const int dev_id = priv->dev->device; + + return ((dev_id == PCI_DEVICE_ID_EXAR_XR17V4358) || + (dev_id == PCI_DEVICE_ID_EXAR_XR17V8358)); +} + static int pci_xr17v35x_setup(struct serial_private *priv, const struct pciserial_board *board, @@ -1846,6 +1783,13 @@ pci_xr17v35x_setup(struct serial_private *priv, port->port.flags |= UPF_EXAR_EFR; /* + * Setup the uart clock for the devices on expansion slot to + * half the clock speed of the main chip (which is 125MHz) + */ + if (xr17v35x_has_slave(priv) && idx >= 8) + port->port.uartclk = (7812500 * 16 / 2); + + /* * Setup Multipurpose Input/Output pins. */ if (idx == 0) { @@ -1997,8 +1941,7 @@ pci_wch_ch38x_setup(struct serial_private *priv, #define PCIE_VENDOR_ID_WCH 0x1c00 #define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250 #define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470 - -#define PCI_DEVICE_ID_EXAR_XR17V8358 0x8358 +#define PCIE_DEVICE_ID_WCH_CH382_2S 0x3253 #define PCI_VENDOR_ID_PERICOM 0x12D8 #define PCI_DEVICE_ID_PERICOM_PI7C9X7951 0x7951 @@ -2113,42 +2056,28 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { }, { .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_PNW_UART1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pnw_serial_setup, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_PNW_UART2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .setup = pnw_serial_setup, - }, - { - .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_PNW_UART3, + .device = PCI_DEVICE_ID_INTEL_BSW_UART1, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = pnw_serial_setup, + .setup = byt_serial_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_TNG_UART, + .device = PCI_DEVICE_ID_INTEL_BSW_UART2, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - .setup = tng_serial_setup, + .setup = byt_serial_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BSW_UART1, + .device = PCI_DEVICE_ID_INTEL_BDW_UART1, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = byt_serial_setup, }, { .vendor = PCI_VENDOR_ID_INTEL, - .device = PCI_DEVICE_ID_INTEL_BSW_UART2, + .device = PCI_DEVICE_ID_INTEL_BDW_UART2, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, .setup = byt_serial_setup, @@ -2515,6 +2444,13 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { }, { .vendor = PCI_VENDOR_ID_EXAR, + .device = PCI_DEVICE_ID_EXAR_XR17V4358, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_xr17v35x_setup, + }, + { + .vendor = PCI_VENDOR_ID_EXAR, .device = PCI_DEVICE_ID_EXAR_XR17V8358, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, @@ -2702,6 +2638,14 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .subdevice = PCI_ANY_ID, .setup = pci_wch_ch353_setup, }, + /* WCH CH382 2S card (16850 clone) */ + { + .vendor = PCIE_VENDOR_ID_WCH, + .device = PCIE_DEVICE_ID_WCH_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, @@ -2999,6 +2943,7 @@ enum pci_board_num_t { pbn_exar_XR17V352, pbn_exar_XR17V354, pbn_exar_XR17V358, + pbn_exar_XR17V4358, pbn_exar_XR17V8358, pbn_exar_ibm_saturn, pbn_pasemi_1682M, @@ -3012,8 +2957,6 @@ enum pci_board_num_t { pbn_ADDIDATA_PCIe_8_3906250, pbn_ce4100_1_115200, pbn_byt, - pbn_pnw, - pbn_tng, pbn_qrk, pbn_omegapci, pbn_NETMOS9900_2s_115200, @@ -3021,6 +2964,7 @@ enum pci_board_num_t { pbn_fintek_4, pbn_fintek_8, pbn_fintek_12, + pbn_wch382_2, pbn_wch384_4, pbn_pericom_PI7C9X7951, pbn_pericom_PI7C9X7952, @@ -3690,6 +3634,14 @@ static struct pciserial_board pci_boards[] = { .reg_shift = 0, .first_offset = 0, }, + [pbn_exar_XR17V4358] = { + .flags = FL_BASE0, + .num_ports = 12, + .base_baud = 7812500, + .uart_offset = 0x400, + .reg_shift = 0, + .first_offset = 0, + }, [pbn_exar_XR17V8358] = { .flags = FL_BASE0, .num_ports = 16, @@ -3792,16 +3744,6 @@ static struct pciserial_board pci_boards[] = { .uart_offset = 0x80, .reg_shift = 2, }, - [pbn_pnw] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 115200, - }, - [pbn_tng] = { - .flags = FL_BASE0, - .num_ports = 1, - .base_baud = 1843200, - }, [pbn_qrk] = { .flags = FL_BASE0, .num_ports = 1, @@ -3843,6 +3785,13 @@ static struct pciserial_board pci_boards[] = { .base_baud = 115200, .first_offset = 0x40, }, + [pbn_wch382_2] = { + .flags = FL_BASE0, + .num_ports = 2, + .base_baud = 115200, + .uart_offset = 8, + .first_offset = 0xC0, + }, [pbn_wch384_4] = { .flags = FL_BASE0, .num_ports = 4, @@ -3890,6 +3839,13 @@ static const struct pci_device_id blacklist[] = { { PCI_DEVICE(0x4348, 0x5053), }, /* WCH CH353 1S1P */ { PCI_DEVICE(0x1c00, 0x3250), }, /* WCH CH382 2S1P */ { PCI_DEVICE(0x1c00, 0x3470), }, /* WCH CH384 4S */ + + /* Intel platforms with MID UART */ + { PCI_VDEVICE(INTEL, 0x081b), }, + { PCI_VDEVICE(INTEL, 0x081c), }, + { PCI_VDEVICE(INTEL, 0x081d), }, + { PCI_VDEVICE(INTEL, 0x1191), }, + { PCI_VDEVICE(INTEL, 0x19d8), }, }; /* @@ -5133,6 +5089,10 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_exar_XR17V358 }, + { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V4358, + PCI_ANY_ID, PCI_ANY_ID, + 0, + 0, pbn_exar_XR17V4358 }, { PCI_VENDOR_ID_EXAR, PCI_DEVICE_ID_EXAR_XR17V8358, PCI_ANY_ID, PCI_ANY_ID, 0, @@ -5582,25 +5542,15 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, pbn_byt }, - /* - * Intel Penwell - */ - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART1, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pnw}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pnw}, - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PNW_UART3, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pnw}, - - /* - * Intel Tangier - */ - { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TNG_UART, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_tng}, + /* Intel Broadwell */ + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART1, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, + pbn_byt }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BDW_UART2, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xff0000, + pbn_byt }, /* * Intel Quark x1000 @@ -5641,6 +5591,10 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_bt_2_115200 }, + { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH382_2S, + PCI_ANY_ID, PCI_ANY_ID, + 0, 0, pbn_wch382_2 }, + { PCIE_VENDOR_ID_WCH, PCIE_DEVICE_ID_WCH_CH384_4S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_wch384_4 }, diff --git a/kernel/drivers/tty/serial/8250/8250_port.c b/kernel/drivers/tty/serial/8250/8250_port.c new file mode 100644 index 000000000..5568d70ee --- /dev/null +++ b/kernel/drivers/tty/serial/8250/8250_port.c @@ -0,0 +1,2935 @@ +/* + * Base port operations for 8250/16550-type serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Split from 8250_core.c, Copyright (C) 2001 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * A note about mapbase / membase + * + * mapbase is the physical address of the IO port. + * membase is an 'ioremapped' cookie. + */ + +#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/tty.h> +#include <linux/ratelimit.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> +#include <linux/serial_8250.h> +#include <linux/nmi.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/kdb.h> +#include <linux/uaccess.h> +#include <linux/pm_runtime.h> + +#include <asm/io.h> +#include <asm/irq.h> + +#include "8250.h" + +/* + * Debugging. + */ +#if 0 +#define DEBUG_AUTOCONF(fmt...) printk(fmt) +#else +#define DEBUG_AUTOCONF(fmt...) do { } while (0) +#endif + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +/* + * Here we define the default xmit fifo size used for each type of UART. + */ +static const struct serial8250_config uart_config[] = { + [PORT_UNKNOWN] = { + .name = "unknown", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_8250] = { + .name = "8250", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16450] = { + .name = "16450", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16550] = { + .name = "16550", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16550A] = { + .name = "16550A", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .rxtrig_bytes = {1, 4, 8, 14}, + .flags = UART_CAP_FIFO, + }, + [PORT_CIRRUS] = { + .name = "Cirrus", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16650] = { + .name = "ST16650", + .fifo_size = 1, + .tx_loadsz = 1, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16650V2] = { + .name = "ST16650V2", + .fifo_size = 32, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | + UART_FCR_T_TRIG_00, + .rxtrig_bytes = {8, 16, 24, 28}, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16750] = { + .name = "TI16750", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | + UART_FCR7_64BYTE, + .rxtrig_bytes = {1, 16, 32, 56}, + .flags = UART_CAP_FIFO | UART_CAP_SLEEP | UART_CAP_AFE, + }, + [PORT_STARTECH] = { + .name = "Startech", + .fifo_size = 1, + .tx_loadsz = 1, + }, + [PORT_16C950] = { + .name = "16C950/954", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + /* UART_CAP_EFR breaks billionon CF bluetooth card. */ + .flags = UART_CAP_FIFO | UART_CAP_SLEEP, + }, + [PORT_16654] = { + .name = "ST16654", + .fifo_size = 64, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | + UART_FCR_T_TRIG_10, + .rxtrig_bytes = {8, 16, 56, 60}, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_16850] = { + .name = "XR16850", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP, + }, + [PORT_RSA] = { + .name = "RSA", + .fifo_size = 2048, + .tx_loadsz = 2048, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11, + .flags = UART_CAP_FIFO, + }, + [PORT_NS16550A] = { + .name = "NS16550A", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_NATSEMI, + }, + [PORT_XSCALE] = { + .name = "XScale", + .fifo_size = 32, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_UUE | UART_CAP_RTOIE, + }, + [PORT_OCTEON] = { + .name = "OCTEON", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO, + }, + [PORT_AR7] = { + .name = "AR7", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_U6_16550A] = { + .name = "U6_16550A", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_TEGRA] = { + .name = "Tegra", + .fifo_size = 32, + .tx_loadsz = 8, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01 | + UART_FCR_T_TRIG_01, + .rxtrig_bytes = {1, 4, 8, 14}, + .flags = UART_CAP_FIFO | UART_CAP_RTOIE, + }, + [PORT_XR17D15X] = { + .name = "XR17D15X", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP, + }, + [PORT_XR17V35X] = { + .name = "XR17V35X", + .fifo_size = 256, + .tx_loadsz = 256, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_11 | + UART_FCR_T_TRIG_11, + .flags = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP, + }, + [PORT_LPC3220] = { + .name = "LPC3220", + .fifo_size = 64, + .tx_loadsz = 32, + .fcr = UART_FCR_DMA_SELECT | UART_FCR_ENABLE_FIFO | + UART_FCR_R_TRIG_00 | UART_FCR_T_TRIG_00, + .flags = UART_CAP_FIFO, + }, + [PORT_BRCM_TRUMANAGE] = { + .name = "TruManage", + .fifo_size = 1, + .tx_loadsz = 1024, + .flags = UART_CAP_HFIFO, + }, + [PORT_8250_CIR] = { + .name = "CIR port" + }, + [PORT_ALTR_16550_F32] = { + .name = "Altera 16550 FIFO32", + .fifo_size = 32, + .tx_loadsz = 32, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_ALTR_16550_F64] = { + .name = "Altera 16550 FIFO64", + .fifo_size = 64, + .tx_loadsz = 64, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, + [PORT_ALTR_16550_F128] = { + .name = "Altera 16550 FIFO128", + .fifo_size = 128, + .tx_loadsz = 128, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .flags = UART_CAP_FIFO | UART_CAP_AFE, + }, +/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement +workaround of errata A-008006 which states that tx_loadsz should be +configured less than Maximum supported fifo bytes */ + [PORT_16550A_FSL64] = { + .name = "16550A_FSL64", + .fifo_size = 64, + .tx_loadsz = 63, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | + UART_FCR7_64BYTE, + .flags = UART_CAP_FIFO, + }, + [PORT_RT2880] = { + .name = "Palmchip BK-3103", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .rxtrig_bytes = {1, 4, 8, 14}, + .flags = UART_CAP_FIFO, + }, +}; + +/* Uart divisor latch read */ +static int default_serial_dl_read(struct uart_8250_port *up) +{ + return serial_in(up, UART_DLL) | serial_in(up, UART_DLM) << 8; +} + +/* Uart divisor latch write */ +static void default_serial_dl_write(struct uart_8250_port *up, int value) +{ + serial_out(up, UART_DLL, value & 0xff); + serial_out(up, UART_DLM, value >> 8 & 0xff); +} + +#ifdef CONFIG_SERIAL_8250_RT288X + +/* Au1x00/RT288x UART hardware has a weird register layout */ +static const s8 au_io_in_map[8] = { + 0, /* UART_RX */ + 2, /* UART_IER */ + 3, /* UART_IIR */ + 5, /* UART_LCR */ + 6, /* UART_MCR */ + 7, /* UART_LSR */ + 8, /* UART_MSR */ + -1, /* UART_SCR (unmapped) */ +}; + +static const s8 au_io_out_map[8] = { + 1, /* UART_TX */ + 2, /* UART_IER */ + 4, /* UART_FCR */ + 5, /* UART_LCR */ + 6, /* UART_MCR */ + -1, /* UART_LSR (unmapped) */ + -1, /* UART_MSR (unmapped) */ + -1, /* UART_SCR (unmapped) */ +}; + +static unsigned int au_serial_in(struct uart_port *p, int offset) +{ + if (offset >= ARRAY_SIZE(au_io_in_map)) + return UINT_MAX; + offset = au_io_in_map[offset]; + if (offset < 0) + return UINT_MAX; + return __raw_readl(p->membase + (offset << p->regshift)); +} + +static void au_serial_out(struct uart_port *p, int offset, int value) +{ + if (offset >= ARRAY_SIZE(au_io_out_map)) + return; + offset = au_io_out_map[offset]; + if (offset < 0) + return; + __raw_writel(value, p->membase + (offset << p->regshift)); +} + +/* Au1x00 haven't got a standard divisor latch */ +static int au_serial_dl_read(struct uart_8250_port *up) +{ + return __raw_readl(up->port.membase + 0x28); +} + +static void au_serial_dl_write(struct uart_8250_port *up, int value) +{ + __raw_writel(value, up->port.membase + 0x28); +} + +#endif + +static unsigned int hub6_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + outb(p->hub6 - 1 + offset, p->iobase); + return inb(p->iobase + 1); +} + +static void hub6_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + outb(p->hub6 - 1 + offset, p->iobase); + outb(value, p->iobase + 1); +} + +static unsigned int mem_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return readb(p->membase + offset); +} + +static void mem_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + writeb(value, p->membase + offset); +} + +static void mem32_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + writel(value, p->membase + offset); +} + +static unsigned int mem32_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return readl(p->membase + offset); +} + +static void mem32be_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + iowrite32be(value, p->membase + offset); +} + +static unsigned int mem32be_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return ioread32be(p->membase + offset); +} + +static unsigned int io_serial_in(struct uart_port *p, int offset) +{ + offset = offset << p->regshift; + return inb(p->iobase + offset); +} + +static void io_serial_out(struct uart_port *p, int offset, int value) +{ + offset = offset << p->regshift; + outb(value, p->iobase + offset); +} + +static int serial8250_default_handle_irq(struct uart_port *port); +static int exar_handle_irq(struct uart_port *port); + +static void set_io_from_upio(struct uart_port *p) +{ + struct uart_8250_port *up = up_to_u8250p(p); + + up->dl_read = default_serial_dl_read; + up->dl_write = default_serial_dl_write; + + switch (p->iotype) { + case UPIO_HUB6: + p->serial_in = hub6_serial_in; + p->serial_out = hub6_serial_out; + break; + + case UPIO_MEM: + p->serial_in = mem_serial_in; + p->serial_out = mem_serial_out; + break; + + case UPIO_MEM32: + p->serial_in = mem32_serial_in; + p->serial_out = mem32_serial_out; + break; + + case UPIO_MEM32BE: + p->serial_in = mem32be_serial_in; + p->serial_out = mem32be_serial_out; + break; + +#ifdef CONFIG_SERIAL_8250_RT288X + case UPIO_AU: + p->serial_in = au_serial_in; + p->serial_out = au_serial_out; + up->dl_read = au_serial_dl_read; + up->dl_write = au_serial_dl_write; + break; +#endif + + default: + p->serial_in = io_serial_in; + p->serial_out = io_serial_out; + break; + } + /* Remember loaded iotype */ + up->cur_iotype = p->iotype; + p->handle_irq = serial8250_default_handle_irq; +} + +static void +serial_port_out_sync(struct uart_port *p, int offset, int value) +{ + switch (p->iotype) { + case UPIO_MEM: + case UPIO_MEM32: + case UPIO_MEM32BE: + case UPIO_AU: + p->serial_out(p, offset, value); + p->serial_in(p, UART_LCR); /* safe, no side-effects */ + break; + default: + p->serial_out(p, offset, value); + } +} + +/* + * For the 16C950 + */ +static void serial_icr_write(struct uart_8250_port *up, int offset, int value) +{ + serial_out(up, UART_SCR, offset); + serial_out(up, UART_ICR, value); +} + +static unsigned int serial_icr_read(struct uart_8250_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; +} + +/* + * FIFO support. + */ +static void serial8250_clear_fifos(struct uart_8250_port *p) +{ + if (p->capabilities & UART_CAP_FIFO) { + serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_out(p, UART_FCR, 0); + } +} + +void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) +{ + serial8250_clear_fifos(p); + serial_out(p, UART_FCR, p->fcr); +} +EXPORT_SYMBOL_GPL(serial8250_clear_and_reinit_fifos); + +void serial8250_rpm_get(struct uart_8250_port *p) +{ + if (!(p->capabilities & UART_CAP_RPM)) + return; + pm_runtime_get_sync(p->port.dev); +} +EXPORT_SYMBOL_GPL(serial8250_rpm_get); + +void serial8250_rpm_put(struct uart_8250_port *p) +{ + if (!(p->capabilities & UART_CAP_RPM)) + return; + pm_runtime_mark_last_busy(p->port.dev); + pm_runtime_put_autosuspend(p->port.dev); +} +EXPORT_SYMBOL_GPL(serial8250_rpm_put); + +/* + * These two wrappers ensure that enable_runtime_pm_tx() can be called more than + * once and disable_runtime_pm_tx() will still disable RPM because the fifo is + * empty and the HW can idle again. + */ +static void serial8250_rpm_get_tx(struct uart_8250_port *p) +{ + unsigned char rpm_active; + + if (!(p->capabilities & UART_CAP_RPM)) + return; + + rpm_active = xchg(&p->rpm_tx_active, 1); + if (rpm_active) + return; + pm_runtime_get_sync(p->port.dev); +} + +static void serial8250_rpm_put_tx(struct uart_8250_port *p) +{ + unsigned char rpm_active; + + if (!(p->capabilities & UART_CAP_RPM)) + return; + + rpm_active = xchg(&p->rpm_tx_active, 0); + if (!rpm_active) + return; + pm_runtime_mark_last_busy(p->port.dev); + pm_runtime_put_autosuspend(p->port.dev); +} + +/* + * IER sleep support. UARTs which have EFRs need the "extended + * capability" bit enabled. Note that on XR16C850s, we need to + * reset LCR to write to IER. + */ +static void serial8250_set_sleep(struct uart_8250_port *p, int sleep) +{ + unsigned char lcr = 0, efr = 0; + /* + * Exar UARTs have a SLEEP register that enables or disables + * each UART to enter sleep mode separately. On the XR17V35x the + * register is accessible to each UART at the UART_EXAR_SLEEP + * offset but the UART channel may only write to the corresponding + * bit. + */ + serial8250_rpm_get(p); + if ((p->port.type == PORT_XR17V35X) || + (p->port.type == PORT_XR17D15X)) { + serial_out(p, UART_EXAR_SLEEP, sleep ? 0xff : 0); + goto out; + } + + if (p->capabilities & UART_CAP_SLEEP) { + if (p->capabilities & UART_CAP_EFR) { + lcr = serial_in(p, UART_LCR); + efr = serial_in(p, UART_EFR); + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, UART_EFR_ECB); + serial_out(p, UART_LCR, 0); + } + serial_out(p, UART_IER, sleep ? UART_IERX_SLEEP : 0); + if (p->capabilities & UART_CAP_EFR) { + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(p, UART_EFR, efr); + serial_out(p, UART_LCR, lcr); + } + } +out: + serial8250_rpm_put(p); +} + +#ifdef CONFIG_SERIAL_8250_RSA +/* + * Attempts to turn on the RSA FIFO. Returns zero on failure. + * We set the port uart clock rate if we succeed. + */ +static int __enable_rsa(struct uart_8250_port *up) +{ + unsigned char mode; + int result; + + mode = serial_in(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + + if (!result) { + serial_out(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); + mode = serial_in(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; + + return result; +} + +static void enable_rsa(struct uart_8250_port *up) +{ + if (up->port.type == PORT_RSA) { + if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + __enable_rsa(up); + spin_unlock_irq(&up->port.lock); + } + if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) + serial_out(up, UART_RSA_FRR, 0); + } +} + +/* + * Attempts to turn off the RSA FIFO. Returns zero on failure. + * It is unknown why interrupts were disabled in here. However, + * the caller is expected to preserve this behaviour by grabbing + * the spinlock before calling this function. + */ +static void disable_rsa(struct uart_8250_port *up) +{ + unsigned char mode; + int result; + + if (up->port.type == PORT_RSA && + up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + + mode = serial_in(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + + if (!result) { + serial_out(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); + mode = serial_in(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; + spin_unlock_irq(&up->port.lock); + } +} +#endif /* CONFIG_SERIAL_8250_RSA */ + +/* + * This is a quickie test to see how big the FIFO is. + * It doesn't work at all the time, more's the pity. + */ +static int size_fifo(struct uart_8250_port *up) +{ + unsigned char old_fcr, old_mcr, old_lcr; + unsigned short old_dl; + int count; + + old_lcr = serial_in(up, UART_LCR); + serial_out(up, UART_LCR, 0); + old_fcr = serial_in(up, UART_FCR); + old_mcr = serial_in(up, UART_MCR); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_out(up, UART_MCR, UART_MCR_LOOP); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + old_dl = serial_dl_read(up); + serial_dl_write(up, 0x0001); + serial_out(up, UART_LCR, 0x03); + for (count = 0; count < 256; count++) + serial_out(up, UART_TX, count); + mdelay(20);/* FIXME - schedule_timeout */ + for (count = 0; (serial_in(up, UART_LSR) & UART_LSR_DR) && + (count < 256); count++) + serial_in(up, UART_RX); + serial_out(up, UART_FCR, old_fcr); + serial_out(up, UART_MCR, old_mcr); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_dl_write(up, old_dl); + serial_out(up, UART_LCR, old_lcr); + + return count; +} + +/* + * Read UART ID using the divisor method - set DLL and DLM to zero + * and the revision will be in DLL and device type in DLM. We + * preserve the device state across this. + */ +static unsigned int autoconfig_read_divisor_id(struct uart_8250_port *p) +{ + unsigned char old_dll, old_dlm, old_lcr; + unsigned int id; + + old_lcr = serial_in(p, UART_LCR); + serial_out(p, UART_LCR, UART_LCR_CONF_MODE_A); + + old_dll = serial_in(p, UART_DLL); + old_dlm = serial_in(p, UART_DLM); + + serial_out(p, UART_DLL, 0); + serial_out(p, UART_DLM, 0); + + id = serial_in(p, UART_DLL) | serial_in(p, UART_DLM) << 8; + + serial_out(p, UART_DLL, old_dll); + serial_out(p, UART_DLM, old_dlm); + serial_out(p, UART_LCR, old_lcr); + + return id; +} + +/* + * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. + * When this function is called we know it is at least a StarTech + * 16650 V2, but it might be one of several StarTech UARTs, or one of + * its clones. (We treat the broken original StarTech 16650 V1 as a + * 16550, and why not? Startech doesn't seem to even acknowledge its + * existence.) + * + * What evil have men's minds wrought... + */ +static void autoconfig_has_efr(struct uart_8250_port *up) +{ + unsigned int id1, id2, id3, rev; + + /* + * Everything with an EFR has SLEEP + */ + up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; + + /* + * First we check to see if it's an Oxford Semiconductor UART. + * + * If we have to do this here because some non-National + * Semiconductor clone chips lock up if you try writing to the + * LSR register (which serial_icr_read does) + */ + + /* + * Check for Oxford Semiconductor 16C950. + * + * EFR [4] must be set else this test fails. + * + * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca) + * claims that it's needed for 952 dual UART's (which are not + * recommended for new designs). + */ + up->acr = 0; + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, UART_LCR, 0x00); + id1 = serial_icr_read(up, UART_ID1); + id2 = serial_icr_read(up, UART_ID2); + id3 = serial_icr_read(up, UART_ID3); + rev = serial_icr_read(up, UART_REV); + + DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev); + + if (id1 == 0x16 && id2 == 0xC9 && + (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) { + up->port.type = PORT_16C950; + + /* + * Enable work around for the Oxford Semiconductor 952 rev B + * chip which causes it to seriously miscalculate baud rates + * when DLL is 0. + */ + if (id3 == 0x52 && rev == 0x01) + up->bugs |= UART_BUG_QUOT; + return; + } + + /* + * We check for a XR16C850 by setting DLL and DLM to 0, and then + * reading back DLL and DLM. The chip type depends on the DLM + * value read back: + * 0x10 - XR16C850 and the DLL contains the chip revision. + * 0x12 - XR16C2850. + * 0x14 - XR16C854. + */ + id1 = autoconfig_read_divisor_id(up); + DEBUG_AUTOCONF("850id=%04x ", id1); + + id2 = id1 >> 8; + if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) { + up->port.type = PORT_16850; + return; + } + + /* + * It wasn't an XR16C850. + * + * We distinguish between the '654 and the '650 by counting + * how many bytes are in the FIFO. I'm using this for now, + * since that's the technique that was sent to me in the + * serial driver update, but I'm not convinced this works. + * I've had problems doing this in the past. -TYT + */ + if (size_fifo(up) == 64) + up->port.type = PORT_16654; + else + up->port.type = PORT_16650V2; +} + +/* + * We detected a chip without a FIFO. Only two fall into + * this category - the original 8250 and the 16450. The + * 16450 has a scratch register (accessible with LCR=0) + */ +static void autoconfig_8250(struct uart_8250_port *up) +{ + unsigned char scratch, status1, status2; + + up->port.type = PORT_8250; + + scratch = serial_in(up, UART_SCR); + serial_out(up, UART_SCR, 0xa5); + status1 = serial_in(up, UART_SCR); + serial_out(up, UART_SCR, 0x5a); + status2 = serial_in(up, UART_SCR); + serial_out(up, UART_SCR, scratch); + + if (status1 == 0xa5 && status2 == 0x5a) + up->port.type = PORT_16450; +} + +static int broken_efr(struct uart_8250_port *up) +{ + /* + * Exar ST16C2550 "A2" devices incorrectly detect as + * having an EFR, and report an ID of 0x0201. See + * http://linux.derkeiler.com/Mailing-Lists/Kernel/2004-11/4812.html + */ + if (autoconfig_read_divisor_id(up) == 0x0201 && size_fifo(up) == 16) + return 1; + + return 0; +} + +/* + * We know that the chip has FIFOs. Does it have an EFR? The + * EFR is located in the same register position as the IIR and + * we know the top two bits of the IIR are currently set. The + * EFR should contain zero. Try to read the EFR. + */ +static void autoconfig_16550a(struct uart_8250_port *up) +{ + unsigned char status1, status2; + unsigned int iersave; + + up->port.type = PORT_16550A; + up->capabilities |= UART_CAP_FIFO; + + /* + * XR17V35x UARTs have an extra divisor register, DLD + * that gets enabled with when DLAB is set which will + * cause the device to incorrectly match and assign + * port type to PORT_16650. The EFR for this UART is + * found at offset 0x09. Instead check the Deice ID (DVID) + * register for a 2, 4 or 8 port UART. + */ + if (up->port.flags & UPF_EXAR_EFR) { + status1 = serial_in(up, UART_EXAR_DVID); + if (status1 == 0x82 || status1 == 0x84 || status1 == 0x88) { + DEBUG_AUTOCONF("Exar XR17V35x "); + up->port.type = PORT_XR17V35X; + up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP; + + return; + } + + } + + /* + * Check for presence of the EFR when DLAB is set. + * Only ST16C650V1 UARTs pass this test. + */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + if (serial_in(up, UART_EFR) == 0) { + serial_out(up, UART_EFR, 0xA8); + if (serial_in(up, UART_EFR) != 0) { + DEBUG_AUTOCONF("EFRv1 "); + up->port.type = PORT_16650; + up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP; + } else { + serial_out(up, UART_LCR, 0); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR7_64BYTE); + status1 = serial_in(up, UART_IIR) >> 5; + serial_out(up, UART_FCR, 0); + serial_out(up, UART_LCR, 0); + + if (status1 == 7) + up->port.type = PORT_16550A_FSL64; + else + DEBUG_AUTOCONF("Motorola 8xxx DUART "); + } + serial_out(up, UART_EFR, 0); + return; + } + + /* + * Maybe it requires 0xbf to be written to the LCR. + * (other ST16C650V2 UARTs, TI16C752A, etc) + */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + if (serial_in(up, UART_EFR) == 0 && !broken_efr(up)) { + DEBUG_AUTOCONF("EFRv2 "); + autoconfig_has_efr(up); + return; + } + + /* + * Check for a National Semiconductor SuperIO chip. + * Attempt to switch to bank 2, read the value of the LOOP bit + * from EXCR1. Switch back to bank 0, change it in MCR. Then + * switch back to bank 2, read it from EXCR1 again and check + * it's changed. If so, set baud_base in EXCR2 to 921600. -- dwmw2 + */ + serial_out(up, UART_LCR, 0); + status1 = serial_in(up, UART_MCR); + serial_out(up, UART_LCR, 0xE0); + status2 = serial_in(up, 0x02); /* EXCR1 */ + + if (!((status2 ^ status1) & UART_MCR_LOOP)) { + serial_out(up, UART_LCR, 0); + serial_out(up, UART_MCR, status1 ^ UART_MCR_LOOP); + serial_out(up, UART_LCR, 0xE0); + status2 = serial_in(up, 0x02); /* EXCR1 */ + serial_out(up, UART_LCR, 0); + serial_out(up, UART_MCR, status1); + + if ((status2 ^ status1) & UART_MCR_LOOP) { + unsigned short quot; + + serial_out(up, UART_LCR, 0xE0); + + quot = serial_dl_read(up); + quot <<= 3; + + if (ns16550a_goto_highspeed(up)) + serial_dl_write(up, quot); + + serial_out(up, UART_LCR, 0); + + up->port.uartclk = 921600*16; + up->port.type = PORT_NS16550A; + up->capabilities |= UART_NATSEMI; + return; + } + } + + /* + * No EFR. Try to detect a TI16750, which only sets bit 5 of + * the IIR when 64 byte FIFO mode is enabled when DLAB is set. + * Try setting it with and without DLAB set. Cheap clones + * set bit 5 without DLAB set. + */ + serial_out(up, UART_LCR, 0); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + status1 = serial_in(up, UART_IIR) >> 5; + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_A); + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + status2 = serial_in(up, UART_IIR) >> 5; + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_out(up, UART_LCR, 0); + + DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2); + + if (status1 == 6 && status2 == 7) { + up->port.type = PORT_16750; + up->capabilities |= UART_CAP_AFE | UART_CAP_SLEEP; + return; + } + + /* + * Try writing and reading the UART_IER_UUE bit (b6). + * If it works, this is probably one of the Xscale platform's + * internal UARTs. + * We're going to explicitly set the UUE bit to 0 before + * trying to write and read a 1 just to make sure it's not + * already a 1 and maybe locked there before we even start start. + */ + iersave = serial_in(up, UART_IER); + serial_out(up, UART_IER, iersave & ~UART_IER_UUE); + if (!(serial_in(up, UART_IER) & UART_IER_UUE)) { + /* + * OK it's in a known zero state, try writing and reading + * without disturbing the current state of the other bits. + */ + serial_out(up, UART_IER, iersave | UART_IER_UUE); + if (serial_in(up, UART_IER) & UART_IER_UUE) { + /* + * It's an Xscale. + * We'll leave the UART_IER_UUE bit set to 1 (enabled). + */ + DEBUG_AUTOCONF("Xscale "); + up->port.type = PORT_XSCALE; + up->capabilities |= UART_CAP_UUE | UART_CAP_RTOIE; + return; + } + } else { + /* + * If we got here we couldn't force the IER_UUE bit to 0. + * Log it and continue. + */ + DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 "); + } + serial_out(up, UART_IER, iersave); + + /* + * Exar uarts have EFR in a weird location + */ + if (up->port.flags & UPF_EXAR_EFR) { + DEBUG_AUTOCONF("Exar XR17D15x "); + up->port.type = PORT_XR17D15X; + up->capabilities |= UART_CAP_AFE | UART_CAP_EFR | + UART_CAP_SLEEP; + + return; + } + + /* + * We distinguish between 16550A and U6 16550A by counting + * how many bytes are in the FIFO. + */ + if (up->port.type == PORT_16550A && size_fifo(up) == 64) { + up->port.type = PORT_U6_16550A; + up->capabilities |= UART_CAP_AFE; + } +} + +/* + * This routine is called by rs_init() to initialize a specific serial + * port. It determines what type of UART chip this serial port is + * using: 8250, 16450, 16550, 16550A. The important question is + * whether or not this UART is a 16550A or not, since this will + * determine whether or not we can use its FIFO features or not. + */ +static void autoconfig(struct uart_8250_port *up) +{ + unsigned char status1, scratch, scratch2, scratch3; + unsigned char save_lcr, save_mcr; + struct uart_port *port = &up->port; + unsigned long flags; + unsigned int old_capabilities; + + if (!port->iobase && !port->mapbase && !port->membase) + return; + + DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04lx, 0x%p): ", + serial_index(port), port->iobase, port->membase); + + /* + * We really do need global IRQs disabled here - we're going to + * be frobbing the chips IRQ enable register to see if it exists. + */ + spin_lock_irqsave(&port->lock, flags); + + up->capabilities = 0; + up->bugs = 0; + + if (!(port->flags & UPF_BUGGY_UART)) { + /* + * Do a simple existence test first; if we fail this, + * there's no point trying anything else. + * + * 0x80 is used as a nonsense port to prevent against + * false positives due to ISA bus float. The + * assumption is that 0x80 is a non-existent port; + * which should be safe since include/asm/io.h also + * makes this assumption. + * + * Note: this is safe as long as MCR bit 4 is clear + * and the device is in "PC" mode. + */ + scratch = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); +#ifdef __i386__ + outb(0xff, 0x080); +#endif + /* + * Mask out IER[7:4] bits for test as some UARTs (e.g. TL + * 16C754B) allow only to modify them if an EFR bit is set. + */ + scratch2 = serial_in(up, UART_IER) & 0x0f; + serial_out(up, UART_IER, 0x0F); +#ifdef __i386__ + outb(0, 0x080); +#endif + scratch3 = serial_in(up, UART_IER) & 0x0f; + serial_out(up, UART_IER, scratch); + if (scratch2 != 0 || scratch3 != 0x0F) { + /* + * We failed; there's nothing here + */ + spin_unlock_irqrestore(&port->lock, flags); + DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", + scratch2, scratch3); + goto out; + } + } + + save_mcr = serial_in(up, UART_MCR); + save_lcr = serial_in(up, UART_LCR); + + /* + * Check to see if a UART is really there. Certain broken + * internal modems based on the Rockwell chipset fail this + * test, because they apparently don't implement the loopback + * test mode. So this test is skipped on the COM 1 through + * COM 4 ports. This *should* be safe, since no board + * manufacturer would be stupid enough to design a board + * that conflicts with COM 1-4 --- we hope! + */ + if (!(port->flags & UPF_SKIP_TEST)) { + 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) { + spin_unlock_irqrestore(&port->lock, flags); + DEBUG_AUTOCONF("LOOP test failed (%02x) ", + status1); + goto out; + } + } + + /* + * We're pretty sure there's a port here. Lets find out what + * type of port it is. The IIR top two bits allows us to find + * out if it's 8250 or 16450, 16550, 16550A or later. This + * determines what we test for next. + * + * We also initialise the EFR (if any) to zero for later. The + * EFR occupies the same register location as the FCR and IIR. + */ + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, 0); + 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: + autoconfig_8250(up); + break; + case 1: + port->type = PORT_UNKNOWN; + break; + case 2: + port->type = PORT_16550; + break; + case 3: + autoconfig_16550a(up); + break; + } + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * Only probe for RSA ports if we got the region. + */ + if (port->type == PORT_16550A && up->probe & UART_PROBE_RSA && + __enable_rsa(up)) + port->type = PORT_RSA; +#endif + + serial_out(up, UART_LCR, save_lcr); + + port->fifosize = uart_config[up->port.type].fifo_size; + old_capabilities = up->capabilities; + up->capabilities = uart_config[port->type].flags; + up->tx_loadsz = uart_config[port->type].tx_loadsz; + + if (port->type == PORT_UNKNOWN) + goto out_lock; + + /* + * Reset the UART. + */ +#ifdef CONFIG_SERIAL_8250_RSA + if (port->type == PORT_RSA) + serial_out(up, UART_RSA_FRR, 0); +#endif + serial_out(up, UART_MCR, save_mcr); + serial8250_clear_fifos(up); + serial_in(up, UART_RX); + if (up->capabilities & UART_CAP_UUE) + serial_out(up, UART_IER, UART_IER_UUE); + else + serial_out(up, UART_IER, 0); + +out_lock: + spin_unlock_irqrestore(&port->lock, flags); + if (up->capabilities != old_capabilities) { + printk(KERN_WARNING + "ttyS%d: detected caps %08x should be %08x\n", + serial_index(port), old_capabilities, + up->capabilities); + } +out: + DEBUG_AUTOCONF("iir=%d ", scratch); + DEBUG_AUTOCONF("type=%s\n", uart_config[port->type].name); +} + +static void autoconfig_irq(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + unsigned char save_mcr, save_ier; + unsigned char save_ICP = 0; + unsigned int ICP = 0; + unsigned long irqs; + int irq; + + if (port->flags & UPF_FOURPORT) { + ICP = (port->iobase & 0xfe0) | 0x1f; + save_ICP = inb_p(ICP); + outb_p(0x80, ICP); + inb_p(ICP); + } + + if (uart_console(port)) + console_lock(); + + /* forget possible initially masked and pending IRQ */ + probe_irq_off(probe_irq_on()); + save_mcr = serial_in(up, UART_MCR); + save_ier = serial_in(up, UART_IER); + serial_out(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); + + irqs = probe_irq_on(); + serial_out(up, UART_MCR, 0); + udelay(10); + if (port->flags & UPF_FOURPORT) { + serial_out(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS); + } else { + serial_out(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + } + serial_out(up, UART_IER, 0x0f); /* enable all intrs */ + serial_in(up, UART_LSR); + serial_in(up, UART_RX); + serial_in(up, UART_IIR); + serial_in(up, UART_MSR); + serial_out(up, UART_TX, 0xFF); + udelay(20); + irq = probe_irq_off(irqs); + + serial_out(up, UART_MCR, save_mcr); + serial_out(up, UART_IER, save_ier); + + if (port->flags & UPF_FOURPORT) + outb_p(save_ICP, ICP); + + if (uart_console(port)) + console_unlock(); + + port->irq = (irq > 0) ? irq : 0; +} + +static inline void __stop_tx(struct uart_8250_port *p) +{ + if (p->ier & UART_IER_THRI) { + p->ier &= ~UART_IER_THRI; + serial_out(p, UART_IER, p->ier); + serial8250_rpm_put_tx(p); + } +} + +static void serial8250_stop_tx(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + serial8250_rpm_get(up); + __stop_tx(up); + + /* + * We really want to stop the transmitter from sending. + */ + if (port->type == PORT_16C950) { + up->acr |= UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } + serial8250_rpm_put(up); +} + +static void serial8250_start_tx(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + serial8250_rpm_get_tx(up); + + if (up->dma && !up->dma->tx_dma(up)) + return; + + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_port_out(port, UART_IER, up->ier); + + if (up->bugs & UART_BUG_TXEN) { + unsigned char lsr; + lsr = serial_in(up, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + if (lsr & UART_LSR_THRE) + serial8250_tx_chars(up); + } + } + + /* + * Re-enable the transmitter if we disabled it. + */ + if (port->type == PORT_16C950 && up->acr & UART_ACR_TXDIS) { + up->acr &= ~UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } +} + +static void serial8250_throttle(struct uart_port *port) +{ + port->throttle(port); +} + +static void serial8250_unthrottle(struct uart_port *port) +{ + port->unthrottle(port); +} + +static void serial8250_stop_rx(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(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); +} + +static void serial8250_disable_ms(struct uart_port *port) +{ + struct uart_8250_port *up = + container_of(port, struct uart_8250_port, port); + + /* no MSR capabilities */ + if (up->bugs & UART_BUG_NOMSR) + return; + + up->ier &= ~UART_IER_MSI; + serial_port_out(port, UART_IER, up->ier); +} + +static void serial8250_enable_ms(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + /* no MSR capabilities */ + if (up->bugs & UART_BUG_NOMSR) + return; + + up->ier |= UART_IER_MSI; + + serial8250_rpm_get(up); + serial_port_out(port, UART_IER, up->ier); + serial8250_rpm_put(up); +} + +/* + * serial8250_rx_chars: processes according to the passed in LSR + * value, and returns the remaining LSR bits not handled + * by this Rx routine. + */ +unsigned char +serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr) +{ + struct uart_port *port = &up->port; + unsigned char ch; + int max_count = 256; + char flag; + + do { + if (likely(lsr & UART_LSR_DR)) + ch = serial_in(up, UART_RX); + else + /* + * Intel 82571 has a Serial Over Lan device that will + * set UART_LSR_BI without setting UART_LSR_DR when + * it receives a break. To avoid reading from the + * receive buffer without UART_LSR_DR bit set, we + * just force the read character to be 0 + */ + ch = 0; + + flag = TTY_NORMAL; + port->icount.rx++; + + lsr |= up->lsr_saved_flags; + up->lsr_saved_flags = 0; + + if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { + if (lsr & UART_LSR_BI) { + lsr &= ~(UART_LSR_FE | UART_LSR_PE); + port->icount.brk++; + /* + * We do the SysRQ and SAK checking + * here because otherwise the break + * may get masked by ignore_status_mask + * or read_status_mask. + */ + if (uart_handle_break(port)) + goto ignore_char; + } else if (lsr & UART_LSR_PE) + port->icount.parity++; + else if (lsr & UART_LSR_FE) + port->icount.frame++; + if (lsr & UART_LSR_OE) + port->icount.overrun++; + + /* + * Mask off conditions which should be ignored. + */ + lsr &= port->read_status_mask; + + if (lsr & UART_LSR_BI) { + DEBUG_INTR("handling break...."); + flag = TTY_BREAK; + } else if (lsr & UART_LSR_PE) + flag = TTY_PARITY; + else if (lsr & UART_LSR_FE) + flag = TTY_FRAME; + } + if (uart_handle_sysrq_char(port, ch)) + goto ignore_char; + + uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); + +ignore_char: + lsr = serial_in(up, UART_LSR); + } while ((lsr & (UART_LSR_DR | UART_LSR_BI)) && (--max_count > 0)); + spin_unlock(&port->lock); + tty_flip_buffer_push(&port->state->port); + spin_lock(&port->lock); + return lsr; +} +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; + int count; + + if (port->x_char) { + serial_out(up, UART_TX, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + if (uart_tx_stopped(port)) { + serial8250_stop_tx(port); + return; + } + if (uart_circ_empty(xmit)) { + __stop_tx(up); + return; + } + + count = up->tx_loadsz; + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + if (up->capabilities & UART_CAP_HFIFO) { + if ((serial_port_in(port, UART_LSR) & BOTH_EMPTY) != + BOTH_EMPTY) + break; + } + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + DEBUG_INTR("THRE..."); + + /* + * With RPM enabled, we have to wait until the FIFO is empty before 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)) + __stop_tx(up); +} +EXPORT_SYMBOL_GPL(serial8250_tx_chars); + +/* Caller holds uart port lock */ +unsigned int serial8250_modem_status(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + unsigned int status = serial_in(up, UART_MSR); + + status |= up->msr_saved_flags; + up->msr_saved_flags = 0; + if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI && + port->state != NULL) { + if (status & UART_MSR_TERI) + port->icount.rng++; + if (status & UART_MSR_DDSR) + port->icount.dsr++; + if (status & UART_MSR_DDCD) + uart_handle_dcd_change(port, status & UART_MSR_DCD); + if (status & UART_MSR_DCTS) + uart_handle_cts_change(port, status & UART_MSR_CTS); + + wake_up_interruptible(&port->state->port.delta_msr_wait); + } + + return status; +} +EXPORT_SYMBOL_GPL(serial8250_modem_status); + +/* + * This handles the interrupt from one port. + */ +int serial8250_handle_irq(struct uart_port *port, unsigned int iir) +{ + unsigned char status; + unsigned long flags; + struct uart_8250_port *up = up_to_u8250p(port); + int dma_err = 0; + + if (iir & UART_IIR_NO_INT) + return 0; + + spin_lock_irqsave(&port->lock, flags); + + status = serial_port_in(port, UART_LSR); + + DEBUG_INTR("status = %x...", status); + + if (status & (UART_LSR_DR | UART_LSR_BI)) { + if (up->dma) + dma_err = up->dma->rx_dma(up, iir); + + if (!up->dma || dma_err) + status = serial8250_rx_chars(up, status); + } + serial8250_modem_status(up); + if ((!up->dma || (up->dma && up->dma->tx_err)) && + (status & UART_LSR_THRE)) + serial8250_tx_chars(up); + + spin_unlock_irqrestore(&port->lock, flags); + return 1; +} +EXPORT_SYMBOL_GPL(serial8250_handle_irq); + +static int serial8250_default_handle_irq(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned int iir; + int ret; + + serial8250_rpm_get(up); + + iir = serial_port_in(port, UART_IIR); + ret = serial8250_handle_irq(port, iir); + + serial8250_rpm_put(up); + return ret; +} + +/* + * These Exar UARTs have an extra interrupt indicator that could + * fire for a few unimplemented interrupts. One of which is a + * wakeup event when coming out of sleep. Put this here just + * to be on the safe side that these interrupts don't go unhandled. + */ +static int exar_handle_irq(struct uart_port *port) +{ + unsigned char int0, int1, int2, int3; + unsigned int iir = serial_port_in(port, UART_IIR); + int ret; + + ret = serial8250_handle_irq(port, iir); + + if ((port->type == PORT_XR17V35X) || + (port->type == PORT_XR17D15X)) { + int0 = serial_port_in(port, 0x80); + int1 = serial_port_in(port, 0x81); + int2 = serial_port_in(port, 0x82); + int3 = serial_port_in(port, 0x83); + } + + return ret; +} + +static unsigned int serial8250_tx_empty(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned long flags; + unsigned int lsr; + + serial8250_rpm_get(up); + + spin_lock_irqsave(&port->lock, flags); + lsr = serial_port_in(port, UART_LSR); + up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS; + spin_unlock_irqrestore(&port->lock, flags); + + serial8250_rpm_put(up); + + return (lsr & BOTH_EMPTY) == BOTH_EMPTY ? TIOCSER_TEMT : 0; +} + +static unsigned int serial8250_get_mctrl(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned int status; + unsigned int ret; + + serial8250_rpm_get(up); + status = serial8250_modem_status(up); + serial8250_rpm_put(up); + + ret = 0; + if (status & UART_MSR_DCD) + ret |= TIOCM_CAR; + if (status & UART_MSR_RI) + ret |= TIOCM_RNG; + if (status & UART_MSR_DSR) + ret |= TIOCM_DSR; + if (status & UART_MSR_CTS) + ret |= TIOCM_CTS; + return ret; +} + +void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned char mcr = 0; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; + + serial_port_out(port, UART_MCR, mcr); +} +EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl); + +static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + if (port->set_mctrl) + port->set_mctrl(port, mctrl); + else + serial8250_do_set_mctrl(port, mctrl); +} + +static void serial8250_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned long flags; + + serial8250_rpm_get(up); + spin_lock_irqsave(&port->lock, flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_port_out(port, UART_LCR, up->lcr); + spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); +} + +/* + * Wait for transmitter & holding register to empty + */ +static void wait_for_xmitr(struct uart_8250_port *up, int bits) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + for (;;) { + status = serial_in(up, UART_LSR); + + up->lsr_saved_flags |= status & LSR_SAVE_FLAGS; + + if ((status & bits) == bits) + break; + if (--tmout == 0) + break; + udelay(1); + } + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & UPF_CONS_FLOW) { + unsigned int tmout; + for (tmout = 1000000; tmout; tmout--) { + unsigned int msr = serial_in(up, UART_MSR); + up->msr_saved_flags |= msr & MSR_SAVE_FLAGS; + if (msr & UART_MSR_CTS) + break; + udelay(1); + touch_nmi_watchdog(); + } + } +} + +#ifdef CONFIG_CONSOLE_POLL +/* + * Console polling routines for writing and reading from the uart while + * in an interrupt or debug context. + */ + +static int serial8250_get_poll_char(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned char lsr; + int status; + + serial8250_rpm_get(up); + + lsr = serial_port_in(port, UART_LSR); + + if (!(lsr & UART_LSR_DR)) { + status = NO_POLL_CHAR; + goto out; + } + + status = serial_port_in(port, UART_RX); +out: + serial8250_rpm_put(up); + return status; +} + + +static void serial8250_put_poll_char(struct uart_port *port, + unsigned char c) +{ + unsigned int ier; + struct uart_8250_port *up = up_to_u8250p(port); + + serial8250_rpm_get(up); + /* + * First save the IER then disable the interrupts + */ + ier = serial_port_in(port, UART_IER); + if (up->capabilities & UART_CAP_UUE) + serial_port_out(port, UART_IER, UART_IER_UUE); + else + serial_port_out(port, UART_IER, 0); + + wait_for_xmitr(up, BOTH_EMPTY); + /* + * Send the character out. + */ + serial_port_out(port, UART_TX, c); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); + serial_port_out(port, UART_IER, ier); + serial8250_rpm_put(up); +} + +#endif /* CONFIG_CONSOLE_POLL */ + +int serial8250_do_startup(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned long flags; + unsigned char lsr, iir; + int retval; + + if (!port->fifosize) + port->fifosize = uart_config[port->type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[port->type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[port->type].flags; + up->mcr = 0; + + if (port->iotype != up->cur_iotype) + set_io_from_upio(port); + + serial8250_rpm_get(up); + if (port->type == PORT_16C950) { + /* Wake up and initialize UART */ + up->acr = 0; + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + serial_port_out(port, UART_EFR, UART_EFR_ECB); + serial_port_out(port, UART_IER, 0); + serial_port_out(port, UART_LCR, 0); + serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + serial_port_out(port, UART_EFR, UART_EFR_ECB); + serial_port_out(port, UART_LCR, 0); + } + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * If this is an RSA port, see if we can kick it up to the + * higher speed clock. + */ + enable_rsa(up); +#endif + + if (port->type == PORT_XR17V35X) { + /* + * First enable access to IER [7:5], ISR [5:4], FCR [5:4], + * MCR [7:5] and MSR [7:0] + */ + serial_port_out(port, UART_XR_EFR, UART_EFR_ECB); + + /* + * Make sure all interrups are masked until initialization is + * complete and the FIFOs are cleared + */ + serial_port_out(port, UART_IER, 0); + } + + /* + * Clear the FIFO buffers and disable them. + * (they will be reenabled in set_termios()) + */ + serial8250_clear_fifos(up); + + /* + * Clear the interrupt registers. + */ + serial_port_in(port, UART_LSR); + serial_port_in(port, UART_RX); + serial_port_in(port, UART_IIR); + serial_port_in(port, UART_MSR); + + /* + * At this point, there's no way the LSR could still be 0xff; + * if it is, then bail out, because there's likely no UART + * here. + */ + if (!(port->flags & UPF_BUGGY_UART) && + (serial_port_in(port, UART_LSR) == 0xff)) { + printk_ratelimited(KERN_INFO "ttyS%d: LSR safety check engaged!\n", + serial_index(port)); + retval = -ENODEV; + goto out; + } + + /* + * For a XR16C850, we need to set the trigger levels + */ + if (port->type == PORT_16850) { + unsigned char fctr; + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + fctr = serial_in(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); + serial_port_out(port, UART_FCTR, + fctr | UART_FCTR_TRGD | UART_FCTR_RX); + serial_port_out(port, UART_TRG, UART_TRG_96); + serial_port_out(port, UART_FCTR, + fctr | UART_FCTR_TRGD | UART_FCTR_TX); + serial_port_out(port, UART_TRG, UART_TRG_96); + + serial_port_out(port, UART_LCR, 0); + } + + if (port->irq) { + unsigned char iir1; + /* + * Test for UARTs that do not reassert THRE when the + * transmitter is idle and the interrupt has already + * been cleared. Real 16550s should always reassert + * this interrupt whenever the transmitter is idle and + * the interrupt is enabled. Delays are necessary to + * allow register changes to become visible. + */ + spin_lock_irqsave(&port->lock, flags); + if (up->port.irqflags & IRQF_SHARED) + disable_irq_nosync(port->irq); + + wait_for_xmitr(up, UART_LSR_THRE); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); + udelay(1); /* allow THRE to set */ + iir1 = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); + serial_port_out_sync(port, UART_IER, UART_IER_THRI); + udelay(1); /* allow a working UART time to re-assert THRE */ + iir = serial_port_in(port, UART_IIR); + serial_port_out(port, UART_IER, 0); + + if (port->irqflags & IRQF_SHARED) + enable_irq(port->irq); + spin_unlock_irqrestore(&port->lock, flags); + + /* + * If the interrupt is not reasserted, or we otherwise + * don't trust the iir, setup a timer to kick the UART + * on a regular basis. + */ + if ((!(iir1 & UART_IIR_NO_INT) && (iir & UART_IIR_NO_INT)) || + up->port.flags & UPF_BUG_THRE) { + up->bugs |= UART_BUG_THRE; + } + } + + retval = up->ops->setup_irq(up); + if (retval) + goto out; + + /* + * Now, initialize the UART + */ + serial_port_out(port, UART_LCR, UART_LCR_WLEN8); + + spin_lock_irqsave(&port->lock, flags); + if (up->port.flags & UPF_FOURPORT) { + if (!up->port.irq) + up->port.mctrl |= TIOCM_OUT1; + } else + /* + * Most PC uarts need OUT2 raised to enable interrupts. + */ + if (port->irq) + up->port.mctrl |= TIOCM_OUT2; + + serial8250_set_mctrl(port, port->mctrl); + + /* Serial over Lan (SoL) hack: + Intel 8257x Gigabit ethernet chips have a + 16550 emulation, to be used for Serial Over Lan. + Those chips take a longer time than a normal + serial device to signalize that a transmission + data was queued. Due to that, the above test generally + fails. One solution would be to delay the reading of + iir. However, this is not reliable, since the timeout + is variable. So, let's just don't test if we receive + TX irq. This way, we'll never enable UART_BUG_TXEN. + */ + if (up->port.flags & UPF_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 (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) { + if (!(up->bugs & UART_BUG_TXEN)) { + up->bugs |= UART_BUG_TXEN; + pr_debug("ttyS%d - enabling bad tx status workarounds\n", + serial_index(port)); + } + } else { + up->bugs &= ~UART_BUG_TXEN; + } + +dont_test_tx_en: + spin_unlock_irqrestore(&port->lock, flags); + + /* + * Clear the interrupt registers again for luck, and clear the + * saved flags to avoid getting false values from polling + * routines or the previous session. + */ + serial_port_in(port, UART_LSR); + serial_port_in(port, UART_RX); + serial_port_in(port, UART_IIR); + serial_port_in(port, UART_MSR); + up->lsr_saved_flags = 0; + up->msr_saved_flags = 0; + + /* + * Request DMA channels for both RX and TX. + */ + if (up->dma) { + retval = serial8250_request_dma(up); + if (retval) { + pr_warn_ratelimited("ttyS%d - failed to request DMA\n", + serial_index(port)); + up->dma = NULL; + } + } + + /* + * Set the IER shadow for rx interrupts but defer actual interrupt + * enable until after the FIFOs are enabled; otherwise, an already- + * active sender can swamp the interrupt handler with "too much work". + */ + up->ier = UART_IER_RLSI | UART_IER_RDI; + + if (port->flags & UPF_FOURPORT) { + unsigned int icp; + /* + * Enable interrupts on the AST Fourport board + */ + icp = (port->iobase & 0xfe0) | 0x01f; + outb_p(0x80, icp); + inb_p(icp); + } + retval = 0; +out: + serial8250_rpm_put(up); + return retval; +} +EXPORT_SYMBOL_GPL(serial8250_do_startup); + +static int serial8250_startup(struct uart_port *port) +{ + if (port->startup) + return port->startup(port); + return serial8250_do_startup(port); +} + +void serial8250_do_shutdown(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned long flags; + + serial8250_rpm_get(up); + /* + * Disable interrupts from this port + */ + up->ier = 0; + serial_port_out(port, UART_IER, 0); + + if (up->dma) + serial8250_release_dma(up); + + spin_lock_irqsave(&port->lock, flags); + if (port->flags & UPF_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + inb((port->iobase & 0xfe0) | 0x1f); + port->mctrl |= TIOCM_OUT1; + } else + port->mctrl &= ~TIOCM_OUT2; + + serial8250_set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); + + /* + * Disable break condition and FIFOs + */ + serial_port_out(port, UART_LCR, + serial_port_in(port, UART_LCR) & ~UART_LCR_SBC); + serial8250_clear_fifos(up); + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * Reset the RSA board back to 115kbps compat mode. + */ + disable_rsa(up); +#endif + + /* + * Read data port to reset things, and then unlink from + * the IRQ chain. + */ + serial_port_in(port, UART_RX); + serial8250_rpm_put(up); + + up->ops->release_irq(up); +} +EXPORT_SYMBOL_GPL(serial8250_do_shutdown); + +static void serial8250_shutdown(struct uart_port *port) +{ + if (port->shutdown) + port->shutdown(port); + else + serial8250_do_shutdown(port); +} + +/* + * XR17V35x UARTs have an extra fractional divisor register (DLD) + * Calculate divisor with extra 4-bit fractional portion + */ +static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up, + unsigned int baud, + unsigned int *frac) +{ + struct uart_port *port = &up->port; + unsigned int quot_16; + + quot_16 = DIV_ROUND_CLOSEST(port->uartclk, baud); + *frac = quot_16 & 0x0f; + + return quot_16 >> 4; +} + +static unsigned int serial8250_get_divisor(struct uart_8250_port *up, + unsigned int baud, + unsigned int *frac) +{ + struct uart_port *port = &up->port; + unsigned int quot; + + /* + * Handle magic divisors for baud rates above baud_base on + * SMSC SuperIO chips. + * + */ + if ((port->flags & UPF_MAGIC_MULTIPLIER) && + baud == (port->uartclk/4)) + quot = 0x8001; + else if ((port->flags & UPF_MAGIC_MULTIPLIER) && + baud == (port->uartclk/8)) + quot = 0x8002; + else if (up->port.type == PORT_XR17V35X) + quot = xr17v35x_get_divisor(up, baud, frac); + else + quot = uart_get_divisor(port, baud); + + /* + * Oxford Semi 952 rev B workaround + */ + if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0) + quot++; + + return quot; +} + +static unsigned char serial8250_compute_lcr(struct uart_8250_port *up, + tcflag_t c_cflag) +{ + unsigned char cval; + + switch (c_cflag & CSIZE) { + case CS5: + cval = UART_LCR_WLEN5; + break; + case CS6: + cval = UART_LCR_WLEN6; + break; + case CS7: + cval = UART_LCR_WLEN7; + break; + default: + case CS8: + cval = UART_LCR_WLEN8; + break; + } + + if (c_cflag & CSTOPB) + cval |= UART_LCR_STOP; + if (c_cflag & PARENB) { + cval |= UART_LCR_PARITY; + if (up->bugs & UART_BUG_PARITY) + up->fifo_bug = true; + } + if (!(c_cflag & PARODD)) + cval |= UART_LCR_EPAR; +#ifdef CMSPAR + if (c_cflag & CMSPAR) + cval |= UART_LCR_SPAR; +#endif + + return cval; +} + +static void serial8250_set_divisor(struct uart_port *port, unsigned int baud, + unsigned int quot, unsigned int quot_frac) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + /* Workaround to enable 115200 baud on OMAP1510 internal ports */ + if (is_omap1510_8250(up)) { + if (baud == 115200) { + quot = 1; + serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1); + } else + serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0); + } + + /* + * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2, + * otherwise just set DLAB + */ + if (up->capabilities & UART_NATSEMI) + serial_port_out(port, UART_LCR, 0xe0); + else + serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB); + + serial_dl_write(up, quot); + + /* XR17V35x UARTs have an extra fractional divisor register (DLD) */ + if (up->port.type == PORT_XR17V35X) + serial_port_out(port, 0x2, quot_frac); +} + +static unsigned int +serial8250_get_baud_rate(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int tolerance = port->uartclk / 100; + + /* + * Ask the core to calculate the divisor for us. + * Allow 1% tolerance at the upper limit so uart clks marginally + * slower than nominal still match standard baud rates without + * causing transmission errors. + */ + return uart_get_baud_rate(port, termios, old, + port->uartclk / 16 / 0xffff, + (port->uartclk + tolerance) / 16); +} + +void +serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned char cval; + unsigned long flags; + unsigned int baud, quot, frac = 0; + + cval = serial8250_compute_lcr(up, termios->c_cflag); + + baud = serial8250_get_baud_rate(port, termios, old); + quot = serial8250_get_divisor(up, baud, &frac); + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + serial8250_rpm_get(up); + spin_lock_irqsave(&port->lock, flags); + + up->lcr = cval; /* Save computed LCR */ + + if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) { + /* NOTE: If fifo_bug is not set, a user can set RX_trigger. */ + if ((baud < 2400 && !up->dma) || up->fifo_bug) { + up->fcr &= ~UART_FCR_TRIGGER_MASK; + up->fcr |= UART_FCR_TRIGGER_1; + } + } + + /* + * MCR-based auto flow control. When AFE is enabled, RTS will be + * deasserted when the receive FIFO contains more characters than + * the trigger, or the MCR RTS bit is cleared. In the case where + * the remote UART is not using CTS auto flow control, we must + * have sufficient FIFO entries for the latency of the remote + * UART to respond. IOW, at least 32 bytes of FIFO. + */ + if (up->capabilities & UART_CAP_AFE && port->fifosize >= 32) { + up->mcr &= ~UART_MCR_AFE; + if (termios->c_cflag & CRTSCTS) + up->mcr |= UART_MCR_AFE; + } + + /* + * Update the per-port timeout. + */ + uart_update_timeout(port, termios->c_cflag, baud); + + port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | 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)) + port->read_status_mask |= UART_LSR_BI; + + /* + * Characteres to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_LSR_DR; + + /* + * CTS flow control flag and modem status interrupts + */ + up->ier &= ~UART_IER_MSI; + if (!(up->bugs & UART_BUG_NOMSR) && + UART_ENABLE_MS(&up->port, termios->c_cflag)) + up->ier |= UART_IER_MSI; + if (up->capabilities & UART_CAP_UUE) + up->ier |= UART_IER_UUE; + if (up->capabilities & UART_CAP_RTOIE) + up->ier |= UART_IER_RTOIE; + + serial_port_out(port, UART_IER, up->ier); + + if (up->capabilities & UART_CAP_EFR) { + unsigned char efr = 0; + /* + * TI16C752/Startech hardware flow control. FIXME: + * - TI16C752 requires control thresholds to be set. + * - UART_MCR_RTS is ineffective if auto-RTS mode is enabled. + */ + if (termios->c_cflag & CRTSCTS) + efr |= UART_EFR_CTS; + + serial_port_out(port, UART_LCR, UART_LCR_CONF_MODE_B); + if (port->flags & UPF_EXAR_EFR) + serial_port_out(port, UART_XR_EFR, efr); + else + serial_port_out(port, UART_EFR, efr); + } + + serial8250_set_divisor(port, baud, quot, frac); + + /* + * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR + * is written without DLAB set, this mode will be disabled. + */ + if (port->type == PORT_16750) + serial_port_out(port, UART_FCR, up->fcr); + + serial_port_out(port, UART_LCR, up->lcr); /* reset DLAB */ + if (port->type != PORT_16750) { + /* emulated UARTs (Lucent Venus 167x) need two steps */ + if (up->fcr & UART_FCR_ENABLE_FIFO) + serial_port_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_port_out(port, UART_FCR, up->fcr); /* set fcr */ + } + serial8250_set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); +} +EXPORT_SYMBOL(serial8250_do_set_termios); + +static void +serial8250_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + if (port->set_termios) + port->set_termios(port, termios, old); + else + serial8250_do_set_termios(port, termios, old); +} + +static void +serial8250_set_ldisc(struct uart_port *port, struct ktermios *termios) +{ + if (termios->c_line == N_PPS) { + port->flags |= UPF_HARDPPS_CD; + spin_lock_irq(&port->lock); + serial8250_enable_ms(port); + spin_unlock_irq(&port->lock); + } else { + port->flags &= ~UPF_HARDPPS_CD; + if (!UART_ENABLE_MS(port, termios->c_cflag)) { + spin_lock_irq(&port->lock); + serial8250_disable_ms(port); + spin_unlock_irq(&port->lock); + } + } +} + + +void serial8250_do_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct uart_8250_port *p = up_to_u8250p(port); + + serial8250_set_sleep(p, state != 0); +} +EXPORT_SYMBOL(serial8250_do_pm); + +static void +serial8250_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + if (port->pm) + port->pm(port, state, oldstate); + else + serial8250_do_pm(port, state, oldstate); +} + +static unsigned int serial8250_port_size(struct uart_8250_port *pt) +{ + if (pt->port.mapsize) + return pt->port.mapsize; + if (pt->port.iotype == UPIO_AU) { + if (pt->port.type == PORT_RT2880) + return 0x100; + return 0x1000; + } + if (is_omap1_8250(pt)) + return 0x16 << pt->port.regshift; + + return 8 << pt->port.regshift; +} + +/* + * Resource handling. + */ +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: + case UPIO_TSI: + case UPIO_MEM32: + case UPIO_MEM32BE: + case UPIO_MEM: + if (!port->mapbase) + break; + + if (!request_mem_region(port->mapbase, size, "serial")) { + ret = -EBUSY; + break; + } + + if (port->flags & UPF_IOREMAP) { + port->membase = ioremap_nocache(port->mapbase, size); + if (!port->membase) { + release_mem_region(port->mapbase, size); + ret = -ENOMEM; + } + } + break; + + case UPIO_HUB6: + case UPIO_PORT: + if (!request_region(port->iobase, size, "serial")) + ret = -EBUSY; + break; + } + return ret; +} + +static void serial8250_release_std_resource(struct uart_8250_port *up) +{ + unsigned int size = serial8250_port_size(up); + struct uart_port *port = &up->port; + + switch (port->iotype) { + case UPIO_AU: + case UPIO_TSI: + case UPIO_MEM32: + case UPIO_MEM32BE: + case UPIO_MEM: + if (!port->mapbase) + break; + + if (port->flags & UPF_IOREMAP) { + iounmap(port->membase); + port->membase = NULL; + } + + release_mem_region(port->mapbase, size); + break; + + case UPIO_HUB6: + case UPIO_PORT: + release_region(port->iobase, size); + break; + } +} + +static void serial8250_release_port(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + serial8250_release_std_resource(up); +} + +static int serial8250_request_port(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + return serial8250_request_std_resource(up); +} + +static int fcr_get_rxtrig_bytes(struct uart_8250_port *up) +{ + const struct serial8250_config *conf_type = &uart_config[up->port.type]; + unsigned char bytes; + + bytes = conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(up->fcr)]; + + return bytes ? bytes : -EOPNOTSUPP; +} + +static int bytes_to_fcr_rxtrig(struct uart_8250_port *up, unsigned char bytes) +{ + const struct serial8250_config *conf_type = &uart_config[up->port.type]; + int i; + + if (!conf_type->rxtrig_bytes[UART_FCR_R_TRIG_BITS(UART_FCR_R_TRIG_00)]) + return -EOPNOTSUPP; + + for (i = 1; i < UART_FCR_R_TRIG_MAX_STATE; i++) { + if (bytes < conf_type->rxtrig_bytes[i]) + /* Use the nearest lower value */ + return (--i) << UART_FCR_R_TRIG_SHIFT; + } + + return UART_FCR_R_TRIG_11; +} + +static int do_get_rxtrig(struct tty_port *port) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + struct uart_8250_port *up = + container_of(uport, struct uart_8250_port, port); + + if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1) + return -EINVAL; + + return fcr_get_rxtrig_bytes(up); +} + +static int do_serial8250_get_rxtrig(struct tty_port *port) +{ + int rxtrig_bytes; + + mutex_lock(&port->mutex); + rxtrig_bytes = do_get_rxtrig(port); + mutex_unlock(&port->mutex); + + return rxtrig_bytes; +} + +static ssize_t serial8250_get_attr_rx_trig_bytes(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct tty_port *port = dev_get_drvdata(dev); + int rxtrig_bytes; + + rxtrig_bytes = do_serial8250_get_rxtrig(port); + if (rxtrig_bytes < 0) + return rxtrig_bytes; + + return snprintf(buf, PAGE_SIZE, "%d\n", rxtrig_bytes); +} + +static int do_set_rxtrig(struct tty_port *port, unsigned char bytes) +{ + struct uart_state *state = container_of(port, struct uart_state, port); + struct uart_port *uport = state->uart_port; + struct uart_8250_port *up = + container_of(uport, struct uart_8250_port, port); + int rxtrig; + + if (!(up->capabilities & UART_CAP_FIFO) || uport->fifosize <= 1 || + up->fifo_bug) + return -EINVAL; + + rxtrig = bytes_to_fcr_rxtrig(up, bytes); + if (rxtrig < 0) + return rxtrig; + + serial8250_clear_fifos(up); + up->fcr &= ~UART_FCR_TRIGGER_MASK; + up->fcr |= (unsigned char)rxtrig; + serial_out(up, UART_FCR, up->fcr); + return 0; +} + +static int do_serial8250_set_rxtrig(struct tty_port *port, unsigned char bytes) +{ + int ret; + + mutex_lock(&port->mutex); + ret = do_set_rxtrig(port, bytes); + mutex_unlock(&port->mutex); + + return ret; +} + +static ssize_t serial8250_set_attr_rx_trig_bytes(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct tty_port *port = dev_get_drvdata(dev); + unsigned char bytes; + int ret; + + if (!count) + return -EINVAL; + + ret = kstrtou8(buf, 10, &bytes); + if (ret < 0) + return ret; + + ret = do_serial8250_set_rxtrig(port, bytes); + if (ret < 0) + return ret; + + return count; +} + +static DEVICE_ATTR(rx_trig_bytes, S_IRUSR | S_IWUSR | S_IRGRP, + serial8250_get_attr_rx_trig_bytes, + serial8250_set_attr_rx_trig_bytes); + +static struct attribute *serial8250_dev_attrs[] = { + &dev_attr_rx_trig_bytes.attr, + NULL, + }; + +static struct attribute_group serial8250_dev_attr_group = { + .attrs = serial8250_dev_attrs, + }; + +static void register_dev_spec_attr_grp(struct uart_8250_port *up) +{ + const struct serial8250_config *conf_type = &uart_config[up->port.type]; + + if (conf_type->rxtrig_bytes[0]) + up->port.attr_group = &serial8250_dev_attr_group; +} + +static void serial8250_config_port(struct uart_port *port, int flags) +{ + struct uart_8250_port *up = up_to_u8250p(port); + int ret; + + /* + * Find the region that we can probe for. This in turn + * tells us whether we can probe for the type of port. + */ + ret = serial8250_request_std_resource(up); + if (ret < 0) + return; + + if (port->iotype != up->cur_iotype) + set_io_from_upio(port); + + if (flags & UART_CONFIG_TYPE) + autoconfig(up); + + /* if access method is AU, it is a 16550 with a quirk */ + if (port->type == PORT_16550A && port->iotype == UPIO_AU) + up->bugs |= UART_BUG_NOMSR; + + /* HW bugs may trigger IRQ while IIR == NO_INT */ + if (port->type == PORT_TEGRA) + up->bugs |= UART_BUG_NOMSR; + + if (port->type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) + autoconfig_irq(up); + + if (port->type == PORT_UNKNOWN) + serial8250_release_std_resource(up); + + /* Fixme: probably not the best place for this */ + if ((port->type == PORT_XR17V35X) || + (port->type == PORT_XR17D15X)) + port->handle_irq = exar_handle_irq; + + register_dev_spec_attr_grp(up); + up->fcr = uart_config[up->port.type].fcr; +} + +static int +serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if (ser->irq >= 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) + return -EINVAL; + return 0; +} + +static const char * +serial8250_type(struct uart_port *port) +{ + int type = port->type; + + if (type >= ARRAY_SIZE(uart_config)) + type = 0; + return uart_config[type].name; +} + +static const struct uart_ops serial8250_pops = { + .tx_empty = serial8250_tx_empty, + .set_mctrl = serial8250_set_mctrl, + .get_mctrl = serial8250_get_mctrl, + .stop_tx = serial8250_stop_tx, + .start_tx = serial8250_start_tx, + .throttle = serial8250_throttle, + .unthrottle = serial8250_unthrottle, + .stop_rx = serial8250_stop_rx, + .enable_ms = serial8250_enable_ms, + .break_ctl = serial8250_break_ctl, + .startup = serial8250_startup, + .shutdown = serial8250_shutdown, + .set_termios = serial8250_set_termios, + .set_ldisc = serial8250_set_ldisc, + .pm = serial8250_pm, + .type = serial8250_type, + .release_port = serial8250_release_port, + .request_port = serial8250_request_port, + .config_port = serial8250_config_port, + .verify_port = serial8250_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = serial8250_get_poll_char, + .poll_put_char = serial8250_put_poll_char, +#endif +}; + +void serial8250_init_port(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + + spin_lock_init(&port->lock); + port->ops = &serial8250_pops; + + up->cur_iotype = 0xFF; +} +EXPORT_SYMBOL_GPL(serial8250_init_port); + +void serial8250_set_defaults(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + + if (up->port.flags & UPF_FIXED_TYPE) { + unsigned int type = up->port.type; + + if (!up->port.fifosize) + up->port.fifosize = uart_config[type].fifo_size; + if (!up->tx_loadsz) + up->tx_loadsz = uart_config[type].tx_loadsz; + if (!up->capabilities) + up->capabilities = uart_config[type].flags; + } + + set_io_from_upio(port); + + /* default dma handlers */ + if (up->dma) { + if (!up->dma->tx_dma) + up->dma->tx_dma = serial8250_tx_dma; + if (!up->dma->rx_dma) + up->dma->rx_dma = serial8250_rx_dma; + } +} +EXPORT_SYMBOL_GPL(serial8250_set_defaults); + +#ifdef CONFIG_SERIAL_8250_CONSOLE + +static void serial8250_console_putchar(struct uart_port *port, int ch) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + wait_for_xmitr(up, UART_LSR_THRE); + serial_port_out(port, UART_TX, ch); +} + +/* + * Restore serial console when h/w power-off detected + */ +static void serial8250_console_restore(struct uart_8250_port *up) +{ + struct uart_port *port = &up->port; + struct ktermios termios; + unsigned int baud, quot, frac = 0; + + termios.c_cflag = port->cons->cflag; + if (port->state->port.tty && termios.c_cflag == 0) + termios.c_cflag = port->state->port.tty->termios.c_cflag; + + baud = serial8250_get_baud_rate(port, &termios, NULL); + quot = serial8250_get_divisor(up, baud, &frac); + + serial8250_set_divisor(port, baud, quot, frac); + serial_port_out(port, UART_LCR, up->lcr); + serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +void serial8250_console_write(struct uart_8250_port *up, const char *s, + unsigned int count) +{ + struct uart_port *port = &up->port; + unsigned long flags; + unsigned int ier; + int locked = 1; + + touch_nmi_watchdog(); + + serial8250_rpm_get(up); + + if (port->sysrq) + locked = 0; + else if (oops_in_progress || in_kdb_printk()) + locked = spin_trylock_irqsave(&port->lock, flags); + else + spin_lock_irqsave(&port->lock, flags); + + /* + * First save the IER then disable the interrupts + */ + ier = serial_port_in(port, UART_IER); + + if (up->capabilities & UART_CAP_UUE) + serial_port_out(port, UART_IER, UART_IER_UUE); + else + serial_port_out(port, UART_IER, 0); + + /* check scratch reg to see if port powered off during system sleep */ + if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) { + serial8250_console_restore(up); + up->canary = 0; + } + + uart_console_write(port, s, count, serial8250_console_putchar); + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up, BOTH_EMPTY); + serial_port_out(port, UART_IER, ier); + + /* + * The receive handling will happen properly because the + * receive ready bit will still be set; it is not cleared + * on read. However, modem control will not, we must + * call it if we have saved something in the saved flags + * while processing with interrupts off. + */ + if (up->msr_saved_flags) + serial8250_modem_status(up); + + if (locked) + spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); +} + +static unsigned int probe_baud(struct uart_port *port) +{ + unsigned char lcr, dll, dlm; + unsigned int quot; + + lcr = serial_port_in(port, UART_LCR); + serial_port_out(port, UART_LCR, lcr | UART_LCR_DLAB); + dll = serial_port_in(port, UART_DLL); + dlm = serial_port_in(port, UART_DLM); + serial_port_out(port, UART_LCR, lcr); + + quot = (dlm << 8) | dll; + return (port->uartclk / 16) / quot; +} + +int serial8250_console_setup(struct uart_port *port, char *options, bool probe) +{ + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (!port->iobase && !port->membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else if (probe) + baud = probe_baud(port); + + return uart_set_options(port, port->cons, baud, parity, bits, flow); +} + +#endif /* CONFIG_SERIAL_8250_CONSOLE */ + +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/tty/serial/8250/8250_uniphier.c b/kernel/drivers/tty/serial/8250/8250_uniphier.c new file mode 100644 index 000000000..245edbb68 --- /dev/null +++ b/kernel/drivers/tty/serial/8250/8250_uniphier.c @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include "8250.h" + +/* Most (but not all) of UniPhier UART devices have 64-depth FIFO. */ +#define UNIPHIER_UART_DEFAULT_FIFO_SIZE 64 + +#define UNIPHIER_UART_CHAR_FCR 3 /* Character / FIFO Control Register */ +#define UNIPHIER_UART_LCR_MCR 4 /* Line/Modem Control Register */ +#define UNIPHIER_UART_LCR_SHIFT 8 +#define UNIPHIER_UART_DLR 9 /* Divisor Latch Register */ + +struct uniphier8250_priv { + int line; + struct clk *clk; + spinlock_t atomic_write_lock; +}; + +/* + * The register map is slightly different from that of 8250. + * IO callbacks must be overridden for correct access to FCR, LCR, and MCR. + */ +static unsigned int uniphier_serial_in(struct uart_port *p, int offset) +{ + unsigned int valshift = 0; + + switch (offset) { + case UART_LCR: + valshift = UNIPHIER_UART_LCR_SHIFT; + /* fall through */ + case UART_MCR: + offset = UNIPHIER_UART_LCR_MCR; + break; + default: + break; + } + + offset <<= p->regshift; + + /* + * The return value must be masked with 0xff because LCR and MCR reside + * in the same register that must be accessed by 32-bit write/read. + * 8 or 16 bit access to this hardware result in unexpected behavior. + */ + return (readl(p->membase + offset) >> valshift) & 0xff; +} + +static void uniphier_serial_out(struct uart_port *p, int offset, int value) +{ + unsigned int valshift = 0; + bool normal = false; + + switch (offset) { + case UART_FCR: + offset = UNIPHIER_UART_CHAR_FCR; + break; + case UART_LCR: + valshift = UNIPHIER_UART_LCR_SHIFT; + /* Divisor latch access bit does not exist. */ + value &= ~(UART_LCR_DLAB << valshift); + /* fall through */ + case UART_MCR: + offset = UNIPHIER_UART_LCR_MCR; + break; + default: + normal = true; + break; + } + + offset <<= p->regshift; + + if (normal) { + writel(value, p->membase + offset); + } else { + /* + * Special case: two registers share the same address that + * must be 32-bit accessed. As this is not longer atomic safe, + * take a lock just in case. + */ + struct uniphier8250_priv *priv = p->private_data; + unsigned long flags; + u32 tmp; + + spin_lock_irqsave(&priv->atomic_write_lock, flags); + tmp = readl(p->membase + offset); + tmp &= ~(0xff << valshift); + tmp |= value << valshift; + writel(tmp, p->membase + offset); + spin_unlock_irqrestore(&priv->atomic_write_lock, flags); + } +} + +/* + * This hardware does not have the divisor latch access bit. + * The divisor latch register exists at different address. + * Override dl_read/write callbacks. + */ +static int uniphier_serial_dl_read(struct uart_8250_port *up) +{ + int offset = UNIPHIER_UART_DLR << up->port.regshift; + + return readl(up->port.membase + offset); +} + +static void uniphier_serial_dl_write(struct uart_8250_port *up, int value) +{ + int offset = UNIPHIER_UART_DLR << up->port.regshift; + + writel(value, up->port.membase + offset); +} + +static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port, + struct uniphier8250_priv *priv) +{ + int ret; + u32 prop; + struct device_node *np = dev->of_node; + + ret = of_alias_get_id(np, "serial"); + if (ret < 0) { + dev_err(dev, "failed to get alias id\n"); + return ret; + } + port->line = priv->line = ret; + + /* Get clk rate through clk driver */ + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(priv->clk); + } + + ret = clk_prepare_enable(priv->clk); + if (ret < 0) + return ret; + + port->uartclk = clk_get_rate(priv->clk); + + /* Check for fifo size */ + if (of_property_read_u32(np, "fifo-size", &prop) == 0) + port->fifosize = prop; + else + port->fifosize = UNIPHIER_UART_DEFAULT_FIFO_SIZE; + + return 0; +} + +static int uniphier_uart_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uart_8250_port up; + struct uniphier8250_priv *priv; + struct resource *regs; + void __iomem *membase; + int irq; + int ret; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_err(dev, "failed to get memory resource"); + return -EINVAL; + } + + membase = devm_ioremap(dev, regs->start, resource_size(regs)); + if (!membase) + return -ENOMEM; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "failed to get IRQ number"); + return irq; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + memset(&up, 0, sizeof(up)); + + ret = uniphier_of_serial_setup(dev, &up.port, priv); + if (ret < 0) + return ret; + + spin_lock_init(&priv->atomic_write_lock); + + up.port.dev = dev; + up.port.private_data = priv; + up.port.mapbase = regs->start; + up.port.mapsize = resource_size(regs); + up.port.membase = membase; + up.port.irq = irq; + + up.port.type = PORT_16550A; + up.port.iotype = UPIO_MEM32; + up.port.regshift = 2; + up.port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE; + up.capabilities = UART_CAP_FIFO; + + up.port.serial_in = uniphier_serial_in; + up.port.serial_out = uniphier_serial_out; + up.dl_read = uniphier_serial_dl_read; + up.dl_write = uniphier_serial_dl_write; + + ret = serial8250_register_8250_port(&up); + if (ret < 0) { + dev_err(dev, "failed to register 8250 port\n"); + clk_disable_unprepare(priv->clk); + return ret; + } + + platform_set_drvdata(pdev, priv); + + return 0; +} + +static int uniphier_uart_remove(struct platform_device *pdev) +{ + struct uniphier8250_priv *priv = platform_get_drvdata(pdev); + + serial8250_unregister_port(priv->line); + clk_disable_unprepare(priv->clk); + + return 0; +} + +static const struct of_device_id uniphier_uart_match[] = { + { .compatible = "socionext,uniphier-uart" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, uniphier_uart_match); + +static struct platform_driver uniphier_uart_platform_driver = { + .probe = uniphier_uart_probe, + .remove = uniphier_uart_remove, + .driver = { + .name = "uniphier-uart", + .of_match_table = uniphier_uart_match, + }, +}; +module_platform_driver(uniphier_uart_platform_driver); + +MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>"); +MODULE_DESCRIPTION("UniPhier UART driver"); +MODULE_LICENSE("GPL"); diff --git a/kernel/drivers/tty/serial/8250/Kconfig b/kernel/drivers/tty/serial/8250/Kconfig index c35070356..6412f1455 100644 --- a/kernel/drivers/tty/serial/8250/Kconfig +++ b/kernel/drivers/tty/serial/8250/Kconfig @@ -274,8 +274,8 @@ config SERIAL_8250_ACORN config SERIAL_8250_FSL bool - depends on SERIAL_8250_CONSOLE && PPC_UDBG_16550 - default PPC + depends on SERIAL_8250_CONSOLE + default PPC || ARM || ARM64 config SERIAL_8250_DW tristate "Support for Synopsys DesignWare 8250 quirks" @@ -294,11 +294,12 @@ config SERIAL_8250_EM config SERIAL_8250_RT288X bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support" - depends on SERIAL_8250 && (SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620) + depends on SERIAL_8250 + default y if MIPS_ALCHEMY || SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620 help - If you have a Ralink RT288x/RT305x SoC based board and want to use the - serial port, say Y to this option. The driver can handle up to 2 serial - ports. If unsure, say N. + Selecting this option will add support for the alternate register + layout used by Ralink RT288x/RT305x, Alchemy Au1xxx, and some others. + If unsure, say N. config SERIAL_8250_OMAP tristate "Support for OMAP internal UART (8250 based driver)" @@ -336,9 +337,44 @@ config SERIAL_8250_FINTEK LPC to 4 UART. This device has some RS485 functionality not available through the PNP driver. If unsure, say N. +config SERIAL_8250_LPC18XX + tristate "NXP LPC18xx/43xx serial port support" + depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST) + default ARCH_LPC18XX + help + If you have a LPC18xx/43xx based board and want to use the + serial port, say Y to this option. If unsure, say Y. + config SERIAL_8250_MT6577 bool "Mediatek serial port support" depends on SERIAL_8250 && ARCH_MEDIATEK help If you have a Mediatek based board and want to use the serial port, say Y to this option. If unsure, say N. + +config SERIAL_8250_UNIPHIER + tristate "Support for UniPhier on-chip UART" + depends on SERIAL_8250 && ARCH_UNIPHIER + help + If you have a UniPhier based board and want to use the on-chip + serial ports, say Y to this option. If unsure, say N. + +config SERIAL_8250_INGENIC + bool "Support for Ingenic SoC serial ports" + depends on SERIAL_8250_CONSOLE && OF_FLATTREE + select LIBFDT + select SERIAL_EARLYCON + help + If you have a system using an Ingenic SoC and wish to make use of + its UARTs, say Y to this option. If unsure, say N. + +config SERIAL_8250_MID + tristate "Support for serial ports on Intel MID platforms" + depends on SERIAL_8250 && PCI + select HSU_DMA if SERIAL_8250_DMA + select HSU_DMA_PCI if X86_INTEL_MID + select RATIONAL + help + Selecting this option will enable handling of the extra features + present on the UART found on Intel Medfield SOC and various other + Intel platforms. diff --git a/kernel/drivers/tty/serial/8250/Makefile b/kernel/drivers/tty/serial/8250/Makefile index 31e7cdc68..e177f8681 100644 --- a/kernel/drivers/tty/serial/8250/Makefile +++ b/kernel/drivers/tty/serial/8250/Makefile @@ -2,10 +2,11 @@ # Makefile for the 8250 serial device drivers. # -obj-$(CONFIG_SERIAL_8250) += 8250.o +obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o 8250-y := 8250_core.o 8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o -8250-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o +8250_base-y := 8250_port.o +8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o @@ -22,4 +23,10 @@ obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o +obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o +obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o +obj-$(CONFIG_SERIAL_8250_INGENIC) += 8250_ingenic.o +obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o + +CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt diff --git a/kernel/drivers/tty/serial/Kconfig b/kernel/drivers/tty/serial/Kconfig index 8cd35348f..f38beb28e 100644 --- a/kernel/drivers/tty/serial/Kconfig +++ b/kernel/drivers/tty/serial/Kconfig @@ -115,9 +115,9 @@ config SERIAL_SB1250_DUART_CONSOLE config SERIAL_ATMEL bool "AT91 / AT32 on-chip serial port support" - depends on ARCH_AT91 || AVR32 + depends on ARCH_AT91 || AVR32 || COMPILE_TEST select SERIAL_CORE - select SERIAL_MCTRL_GPIO + select SERIAL_MCTRL_GPIO if GPIOLIB help This enables the driver for the on-chip UARTs of the Atmel AT91 and AT32 processors. @@ -571,7 +571,7 @@ config BFIN_UART3_CTSRTS config SERIAL_IMX tristate "IMX serial port support" - depends on ARCH_MXC + depends on ARCH_MXC || COMPILE_TEST select SERIAL_CORE select RATIONAL help @@ -582,6 +582,7 @@ config SERIAL_IMX_CONSOLE bool "Console on IMX serial port" depends on SERIAL_IMX=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON if OF help If you have enabled the serial port on the Freescale IMX CPU you can make it the console by answering Y to this option. @@ -594,7 +595,7 @@ config SERIAL_IMX_CONSOLE config SERIAL_UARTLITE tristate "Xilinx uartlite serial port support" - depends on PPC32 || MICROBLAZE || MFD_TIMBERDALE || ARCH_ZYNQ + depends on HAS_IOMEM select SERIAL_CORE help Say Y here if you want to use the Xilinx uartlite serial controller. @@ -728,7 +729,7 @@ config SERIAL_IP22_ZILOG_CONSOLE config SERIAL_SH_SCI tristate "SuperH SCI(F) serial port support" - depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST + depends on SUPERH || ARCH_SHMOBILE || H8300 || COMPILE_TEST select SERIAL_CORE config SERIAL_SH_SCI_NR_UARTS @@ -743,7 +744,7 @@ config SERIAL_SH_SCI_CONSOLE config SERIAL_SH_SCI_DMA bool "DMA support" - depends on SERIAL_SH_SCI && SH_DMAE + depends on SERIAL_SH_SCI && DMA_ENGINE config SERIAL_PNX8XXX bool "Enable PNX8XXX SoCs' UART Support" @@ -1067,6 +1068,7 @@ config SERIAL_ETRAXFS bool "ETRAX FS serial port support" depends on ETRAX_ARCH_V32 && OF select SERIAL_CORE + select SERIAL_MCTRL_GPIO if GPIOLIB config SERIAL_ETRAXFS_CONSOLE bool "ETRAX FS serial console support" @@ -1179,15 +1181,42 @@ config SERIAL_SCCNXP_CONSOLE help Support for console on SCCNXP serial ports. +config SERIAL_SC16IS7XX_CORE + tristate + config SERIAL_SC16IS7XX - tristate "SC16IS7xx serial support" - depends on I2C - select SERIAL_CORE - select REGMAP_I2C if I2C - help - This selects support for SC16IS7xx serial ports. - Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752, - SC16IS760 and SC16IS762. + tristate "SC16IS7xx serial support" + select SERIAL_CORE + depends on (SPI_MASTER && !I2C) || 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. + +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. + +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 exsisting driver. + You must select at least one bus for the driver to be built. config SERIAL_BFIN_SPORT tristate "Blackfin SPORT emulate UART" @@ -1349,7 +1378,8 @@ config SERIAL_ALTERA_UART_CONSOLE config SERIAL_IFX6X60 tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)" - depends on GPIOLIB && SPI + depends on GPIOLIB || COMPILE_TEST + depends on SPI && HAS_DMA help Support for the IFX6x60 modem devices on Intel MID platforms. @@ -1378,16 +1408,8 @@ config SERIAL_PCH_UART_CONSOLE (the system console is the device which receives all kernel messages and warnings and which allows logins in single user mode). -config SERIAL_MSM_SMD - bool "Enable tty device interface for some SMD ports" - default n - depends on MSM_SMD - help - Enables userspace clients to read and write to some streaming SMD - ports via tty device interface for MSM chipset. - config SERIAL_MXS_AUART - depends on ARCH_MXS + depends on ARCH_MXS || COMPILE_TEST tristate "MXS AUART support" select SERIAL_CORE select SERIAL_MCTRL_GPIO if GPIOLIB @@ -1524,6 +1546,7 @@ config SERIAL_FSL_LPUART_CONSOLE bool "Console on Freescale lpuart serial port" depends on SERIAL_FSL_LPUART=y select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON help If you have enabled the lpuart serial port on the Freescale SoCs, you can make it the console by answering Y to this option. @@ -1589,6 +1612,23 @@ config SERIAL_SPRD_CONSOLE with "earlycon" on the kernel command line. The console is enabled when early_param is processed. +config SERIAL_STM32 + tristate "STMicroelectronics STM32 serial port support" + select SERIAL_CORE + depends on ARM || COMPILE_TEST + help + This driver is for the on-chip Serial Controller on + STMicroelectronics STM32 MCUs. + USART supports Rx & Tx functionality. + It support all industry standard baud rates. + + If unsure, say N. + +config SERIAL_STM32_CONSOLE + bool "Support for console on STM32" + depends on SERIAL_STM32=y + select SERIAL_CORE_CONSOLE + endmenu config SERIAL_MCTRL_GPIO diff --git a/kernel/drivers/tty/serial/Makefile b/kernel/drivers/tty/serial/Makefile index c3ac3d930..5ab41119b 100644 --- a/kernel/drivers/tty/serial/Makefile +++ b/kernel/drivers/tty/serial/Makefile @@ -53,7 +53,7 @@ obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o obj-$(CONFIG_SERIAL_ETRAXFS) += etraxfs-uart.o obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o -obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o +obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o obj-$(CONFIG_SERIAL_JSM) += jsm/ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o @@ -79,7 +79,6 @@ obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o -obj-$(CONFIG_SERIAL_MSM_SMD) += msm_smd_tty.o obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o @@ -93,6 +92,7 @@ obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o +obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o # GPIOLIB helpers for modem control lines obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o diff --git a/kernel/drivers/tty/serial/altera_jtaguart.c b/kernel/drivers/tty/serial/altera_jtaguart.c index 0fefdd893..32df2a0cb 100644 --- a/kernel/drivers/tty/serial/altera_jtaguart.c +++ b/kernel/drivers/tty/serial/altera_jtaguart.c @@ -387,7 +387,7 @@ console_initcall(altera_jtaguart_console_init); #define ALTERA_JTAGUART_CONSOLE NULL -#endif /* CONFIG_ALTERA_JTAGUART_CONSOLE */ +#endif /* CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE */ static struct uart_driver altera_jtaguart_driver = { .owner = THIS_MODULE, diff --git a/kernel/drivers/tty/serial/altera_uart.c b/kernel/drivers/tty/serial/altera_uart.c index b2859fe07..61b607f24 100644 --- a/kernel/drivers/tty/serial/altera_uart.c +++ b/kernel/drivers/tty/serial/altera_uart.c @@ -493,7 +493,7 @@ console_initcall(altera_uart_console_init); #define ALTERA_UART_CONSOLE NULL -#endif /* CONFIG_ALTERA_UART_CONSOLE */ +#endif /* CONFIG_SERIAL_ALTERA_UART_CONSOLE */ /* * Define the altera_uart UART driver structure. @@ -508,29 +508,6 @@ static struct uart_driver altera_uart_driver = { .cons = ALTERA_UART_CONSOLE, }; -#ifdef CONFIG_OF -static int altera_uart_get_of_uartclk(struct platform_device *pdev, - struct uart_port *port) -{ - int len; - const __be32 *clk; - - clk = of_get_property(pdev->dev.of_node, "clock-frequency", &len); - if (!clk || len < sizeof(__be32)) - return -ENODEV; - - port->uartclk = be32_to_cpup(clk); - - return 0; -} -#else -static int altera_uart_get_of_uartclk(struct platform_device *pdev, - struct uart_port *port) -{ - return -ENODEV; -} -#endif /* CONFIG_OF */ - static int altera_uart_probe(struct platform_device *pdev) { struct altera_uart_platform_uart *platp = dev_get_platdata(&pdev->dev); @@ -570,7 +547,8 @@ static int altera_uart_probe(struct platform_device *pdev) if (platp) port->uartclk = platp->uartclk; else { - ret = altera_uart_get_of_uartclk(pdev, port); + ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &port->uartclk); if (ret) return ret; } diff --git a/kernel/drivers/tty/serial/amba-pl011.c b/kernel/drivers/tty/serial/amba-pl011.c index 841c42ae1..3ff6363b3 100644 --- a/kernel/drivers/tty/serial/amba-pl011.c +++ b/kernel/drivers/tty/serial/amba-pl011.c @@ -58,7 +58,7 @@ #include <linux/pinctrl/consumer.h> #include <linux/sizes.h> #include <linux/io.h> -#include <linux/workqueue.h> +#include <linux/acpi.h> #define UART_NR 14 @@ -79,6 +79,8 @@ struct vendor_data { bool oversampling; bool dma_threshold; bool cts_event_workaround; + bool always_enabled; + bool fixed_options; unsigned int (*get_fifosize)(struct amba_device *dev); }; @@ -95,9 +97,19 @@ static struct vendor_data vendor_arm = { .oversampling = false, .dma_threshold = false, .cts_event_workaround = false, + .always_enabled = false, + .fixed_options = false, .get_fifosize = get_fifosize_arm, }; +static struct vendor_data vendor_sbsa = { + .oversampling = false, + .dma_threshold = false, + .cts_event_workaround = false, + .always_enabled = true, + .fixed_options = true, +}; + static unsigned int get_fifosize_st(struct amba_device *dev) { return 64; @@ -110,6 +122,8 @@ static struct vendor_data vendor_st = { .oversampling = true, .dma_threshold = true, .cts_event_workaround = true, + .always_enabled = false, + .fixed_options = false, .get_fifosize = get_fifosize_st, }; @@ -157,9 +171,8 @@ struct uart_amba_port { unsigned int lcrh_tx; /* vendor-specific */ unsigned int lcrh_rx; /* vendor-specific */ unsigned int old_cr; /* state during shutdown */ - struct delayed_work tx_softirq_work; bool autorts; - unsigned int tx_irq_seen; /* 0=none, 1=1, 2=2 or more */ + unsigned int fixed_baud; /* vendor-set fixed baud rate */ char type[12]; #ifdef CONFIG_DMA_ENGINE /* DMA stuff */ @@ -178,8 +191,8 @@ struct uart_amba_port { */ static int pl011_fifo_to_tty(struct uart_amba_port *uap) { - u16 status, ch; - unsigned int flag, max_count = 256; + u16 status; + unsigned int ch, flag, max_count = 256; int fifotaken = 0; while (max_count--) { @@ -1172,15 +1185,14 @@ static void pl011_stop_tx(struct uart_port *port) pl011_dma_tx_stop(uap); } -static bool pl011_tx_chars(struct uart_amba_port *uap); +static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq); /* Start TX with programmed I/O only (no DMA) */ static void pl011_start_tx_pio(struct uart_amba_port *uap) { uap->im |= UART011_TXIM; writew(uap->im, uap->port.membase + UART011_IMSC); - if (!uap->tx_irq_seen) - pl011_tx_chars(uap); + pl011_tx_chars(uap, false); } static void pl011_start_tx(struct uart_port *port) @@ -1247,15 +1259,11 @@ __acquires(&uap->port.lock) spin_lock(&uap->port.lock); } -/* - * Transmit a character - * - * Returns true if the character was successfully queued to the FIFO. - * Returns false otherwise. - */ -static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c) +static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, + bool from_irq) { - if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) + if (unlikely(!from_irq) && + readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) return false; /* unable to transmit character */ writew(c, uap->port.membase + UART01x_DR); @@ -1264,70 +1272,41 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c) return true; } -static bool pl011_tx_chars(struct uart_amba_port *uap) +static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) { struct circ_buf *xmit = &uap->port.state->xmit; - int count; - - if (unlikely(uap->tx_irq_seen < 2)) - /* - * Initial FIFO fill level unknown: we must check TXFF - * after each write, so just try to fill up the FIFO. - */ - count = uap->fifosize; - else /* tx_irq_seen >= 2 */ - /* - * FIFO initially at least half-empty, so we can simply - * write half the FIFO without polling TXFF. - - * Note: the *first* TX IRQ can still race with - * pl011_start_tx_pio(), which can result in the FIFO - * being fuller than expected in that case. - */ - count = uap->fifosize >> 1; - - /* - * If the FIFO is full we're guaranteed a TX IRQ at some later point, - * and can't transmit immediately in any case: - */ - if (unlikely(uap->tx_irq_seen < 2 && - readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF)) - return false; + int count = uap->fifosize >> 1; if (uap->port.x_char) { - if (!pl011_tx_char(uap, uap->port.x_char)) - goto done; + if (!pl011_tx_char(uap, uap->port.x_char, from_irq)) + return; uap->port.x_char = 0; --count; } if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { pl011_stop_tx(&uap->port); - goto done; + return; } /* If we are using DMA mode, try to send some characters. */ if (pl011_dma_tx_irq(uap)) - goto done; + return; - while (count-- > 0 && pl011_tx_char(uap, xmit->buf[xmit->tail])) { - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - if (uart_circ_empty(xmit)) + do { + if (likely(from_irq) && count-- == 0) break; - } + + if (!pl011_tx_char(uap, xmit->buf[xmit->tail], from_irq)) + break; + + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + } while (!uart_circ_empty(xmit)); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); - if (uart_circ_empty(xmit)) { + if (uart_circ_empty(xmit)) pl011_stop_tx(&uap->port); - goto done; - } - - if (unlikely(!uap->tx_irq_seen)) - schedule_delayed_work(&uap->tx_softirq_work, uap->port.timeout); - -done: - return false; } static void pl011_modem_status(struct uart_amba_port *uap) @@ -1354,26 +1333,23 @@ static void pl011_modem_status(struct uart_amba_port *uap) wake_up_interruptible(&uap->port.state->port.delta_msr_wait); } -static void pl011_tx_softirq(struct work_struct *work) +static void check_apply_cts_event_workaround(struct uart_amba_port *uap) { - struct delayed_work *dwork = to_delayed_work(work); - struct uart_amba_port *uap = - container_of(dwork, struct uart_amba_port, tx_softirq_work); - - spin_lock(&uap->port.lock); - while (pl011_tx_chars(uap)) ; - spin_unlock(&uap->port.lock); -} + unsigned int dummy_read; -static void pl011_tx_irq_seen(struct uart_amba_port *uap) -{ - if (likely(uap->tx_irq_seen > 1)) + if (!uap->vendor->cts_event_workaround) return; - uap->tx_irq_seen++; - if (uap->tx_irq_seen < 2) - /* first TX IRQ */ - cancel_delayed_work(&uap->tx_softirq_work); + /* workaround to make sure that all bits are unlocked.. */ + writew(0x00, uap->port.membase + UART011_ICR); + + /* + * WA: introduce 26ns(1 uart clk) delay before W1C; + * single apb access will incur 2 pclk(133.12Mhz) delay, + * so add 2 dummy reads + */ + dummy_read = readw(uap->port.membase + UART011_ICR); + dummy_read = readw(uap->port.membase + UART011_ICR); } static irqreturn_t pl011_int(int irq, void *dev_id) @@ -1381,25 +1357,15 @@ static irqreturn_t pl011_int(int irq, void *dev_id) struct uart_amba_port *uap = dev_id; unsigned long flags; unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; + u16 imsc; int handled = 0; - unsigned int dummy_read; spin_lock_irqsave(&uap->port.lock, flags); - status = readw(uap->port.membase + UART011_MIS); + imsc = readw(uap->port.membase + UART011_IMSC); + status = readw(uap->port.membase + UART011_RIS) & imsc; if (status) { do { - if (uap->vendor->cts_event_workaround) { - /* workaround to make sure that all bits are unlocked.. */ - writew(0x00, uap->port.membase + UART011_ICR); - - /* - * WA: introduce 26ns(1 uart clk) delay before W1C; - * single apb access will incur 2 pclk(133.12Mhz) delay, - * so add 2 dummy reads - */ - dummy_read = readw(uap->port.membase + UART011_ICR); - dummy_read = readw(uap->port.membase + UART011_ICR); - } + check_apply_cts_event_workaround(uap); writew(status & ~(UART011_TXIS|UART011_RTIS| UART011_RXIS), @@ -1414,15 +1380,13 @@ static irqreturn_t pl011_int(int irq, void *dev_id) if (status & (UART011_DSRMIS|UART011_DCDMIS| UART011_CTSMIS|UART011_RIMIS)) pl011_modem_status(uap); - if (status & UART011_TXIS) { - pl011_tx_irq_seen(uap); - pl011_tx_chars(uap); - } + if (status & UART011_TXIS) + pl011_tx_chars(uap, true); if (pass_counter-- == 0) break; - status = readw(uap->port.membase + UART011_MIS); + status = readw(uap->port.membase + UART011_RIS) & imsc; } while (status != 0); handled = 1; } @@ -1617,6 +1581,32 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) } } +static int pl011_allocate_irq(struct uart_amba_port *uap) +{ + writew(uap->im, uap->port.membase + UART011_IMSC); + + return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); +} + +/* + * Enable interrupts, only timeouts when using DMA + * if initial RX DMA job failed, start in interrupt mode + * as well. + */ +static void pl011_enable_interrupts(struct uart_amba_port *uap) +{ + spin_lock_irq(&uap->port.lock); + + /* Clear out any spuriously appearing RX interrupts */ + writew(UART011_RTIS | UART011_RXIS, + uap->port.membase + UART011_ICR); + uap->im = UART011_RTIM; + if (!pl011_dma_rx_running(uap)) + uap->im |= UART011_RXIM; + writew(uap->im, uap->port.membase + UART011_IMSC); + spin_unlock_irq(&uap->port.lock); +} + static int pl011_startup(struct uart_port *port) { struct uart_amba_port *uap = @@ -1628,20 +1618,12 @@ static int pl011_startup(struct uart_port *port) if (retval) goto clk_dis; - writew(uap->im, uap->port.membase + UART011_IMSC); - - /* - * Allocate the IRQ - */ - retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); + retval = pl011_allocate_irq(uap); if (retval) goto clk_dis; writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); - /* Assume that TX IRQ doesn't work until we see one: */ - uap->tx_irq_seen = 0; - spin_lock_irq(&uap->port.lock); /* restore RTS and DTR */ @@ -1659,20 +1641,7 @@ static int pl011_startup(struct uart_port *port) /* Startup DMA */ pl011_dma_startup(uap); - /* - * Finally, enable interrupts, only timeouts when using DMA - * if initial RX DMA job failed, start in interrupt mode - * as well. - */ - spin_lock_irq(&uap->port.lock); - /* Clear out any spuriously appearing RX interrupts */ - writew(UART011_RTIS | UART011_RXIS, - uap->port.membase + UART011_ICR); - uap->im = UART011_RTIM; - if (!pl011_dma_rx_running(uap)) - uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + UART011_IMSC); - spin_unlock_irq(&uap->port.lock); + pl011_enable_interrupts(uap); return 0; @@ -1681,6 +1650,28 @@ static int pl011_startup(struct uart_port *port) return retval; } +static int sbsa_uart_startup(struct uart_port *port) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + int retval; + + retval = pl011_hwinit(port); + if (retval) + return retval; + + retval = pl011_allocate_irq(uap); + if (retval) + return retval; + + /* The SBSA UART does not support any modem status lines. */ + uap->old_status = 0; + + pl011_enable_interrupts(uap); + + return 0; +} + static void pl011_shutdown_channel(struct uart_amba_port *uap, unsigned int lcrh) { @@ -1691,36 +1682,15 @@ static void pl011_shutdown_channel(struct uart_amba_port *uap, writew(val, uap->port.membase + lcrh); } -static void pl011_shutdown(struct uart_port *port) +/* + * disable the port. It should not disable RTS and DTR. + * Also RTS and DTR state should be preserved to restore + * it during startup(). + */ +static void pl011_disable_uart(struct uart_amba_port *uap) { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); unsigned int cr; - cancel_delayed_work_sync(&uap->tx_softirq_work); - - /* - * disable all interrupts - */ - spin_lock_irq(&uap->port.lock); - uap->im = 0; - writew(uap->im, uap->port.membase + UART011_IMSC); - writew(0xffff, uap->port.membase + UART011_ICR); - spin_unlock_irq(&uap->port.lock); - - pl011_dma_shutdown(uap); - - /* - * Free the interrupt - */ - free_irq(uap->port.irq, uap); - - /* - * disable the port - * disable the port. It should not disable RTS and DTR. - * Also RTS and DTR state should be preserved to restore - * it during startup(). - */ uap->autorts = false; spin_lock_irq(&uap->port.lock); cr = readw(uap->port.membase + UART011_CR); @@ -1736,6 +1706,32 @@ static void pl011_shutdown(struct uart_port *port) pl011_shutdown_channel(uap, uap->lcrh_rx); if (uap->lcrh_rx != uap->lcrh_tx) pl011_shutdown_channel(uap, uap->lcrh_tx); +} + +static void pl011_disable_interrupts(struct uart_amba_port *uap) +{ + spin_lock_irq(&uap->port.lock); + + /* mask all interrupts and clear all pending ones */ + uap->im = 0; + writew(uap->im, uap->port.membase + UART011_IMSC); + writew(0xffff, uap->port.membase + UART011_ICR); + + spin_unlock_irq(&uap->port.lock); +} + +static void pl011_shutdown(struct uart_port *port) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + + pl011_disable_interrupts(uap); + + pl011_dma_shutdown(uap); + + free_irq(uap->port.irq, uap); + + pl011_disable_uart(uap); /* * Shut down the clock producer @@ -1756,6 +1752,51 @@ static void pl011_shutdown(struct uart_port *port) uap->port.ops->flush_buffer(port); } +static void sbsa_uart_shutdown(struct uart_port *port) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + + pl011_disable_interrupts(uap); + + free_irq(uap->port.irq, uap); + + if (uap->port.ops->flush_buffer) + uap->port.ops->flush_buffer(port); +} + +static void +pl011_setup_status_masks(struct uart_port *port, struct ktermios *termios) +{ + port->read_status_mask = UART011_DR_OE | 255; + if (termios->c_iflag & INPCK) + port->read_status_mask |= UART011_DR_FE | UART011_DR_PE; + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) + port->read_status_mask |= UART011_DR_BE; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= UART011_DR_BE; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= UART011_DR_OE; + } + + /* + * Ignore all characters if CREAD is not set. + */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_DR_RX; +} + static void pl011_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -1820,33 +1861,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, */ uart_update_timeout(port, termios->c_cflag, baud); - port->read_status_mask = UART011_DR_OE | 255; - if (termios->c_iflag & INPCK) - port->read_status_mask |= UART011_DR_FE | UART011_DR_PE; - if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) - port->read_status_mask |= UART011_DR_BE; - - /* - * Characters to ignore - */ - port->ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART011_DR_FE | UART011_DR_PE; - if (termios->c_iflag & IGNBRK) { - port->ignore_status_mask |= UART011_DR_BE; - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (termios->c_iflag & IGNPAR) - port->ignore_status_mask |= UART011_DR_OE; - } - - /* - * Ignore all characters if CREAD is not set. - */ - if ((termios->c_cflag & CREAD) == 0) - port->ignore_status_mask |= UART_DUMMY_DR_RX; + pl011_setup_status_masks(port, termios); if (UART_ENABLE_MS(port, termios->c_cflag)) pl011_enable_ms(port); @@ -1901,6 +1916,27 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, spin_unlock_irqrestore(&port->lock, flags); } +static void +sbsa_uart_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct uart_amba_port *uap = + container_of(port, struct uart_amba_port, port); + unsigned long flags; + + tty_termios_encode_baud_rate(termios, uap->fixed_baud, uap->fixed_baud); + + /* The SBSA UART only supports 8n1 without hardware flow control. */ + termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD); + termios->c_cflag &= ~(CMSPAR | CRTSCTS); + termios->c_cflag |= CS8 | CLOCAL; + + spin_lock_irqsave(&port->lock, flags); + uart_update_timeout(port, CS8, uap->fixed_baud); + pl011_setup_status_masks(port, termios); + spin_unlock_irqrestore(&port->lock, flags); +} + static const char *pl011_type(struct uart_port *port) { struct uart_amba_port *uap = @@ -1976,6 +2012,37 @@ static struct uart_ops amba_pl011_pops = { #endif }; +static void sbsa_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static unsigned int sbsa_uart_get_mctrl(struct uart_port *port) +{ + return 0; +} + +static const struct uart_ops sbsa_uart_pops = { + .tx_empty = pl011_tx_empty, + .set_mctrl = sbsa_uart_set_mctrl, + .get_mctrl = sbsa_uart_get_mctrl, + .stop_tx = pl011_stop_tx, + .start_tx = pl011_start_tx, + .stop_rx = pl011_stop_rx, + .startup = sbsa_uart_startup, + .shutdown = sbsa_uart_shutdown, + .set_termios = sbsa_uart_set_termios, + .type = pl011_type, + .release_port = pl011_release_port, + .request_port = pl011_request_port, + .config_port = pl011_config_port, + .verify_port = pl011_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_init = pl011_hwinit, + .poll_get_char = pl011_get_poll_char, + .poll_put_char = pl011_put_poll_char, +#endif +}; + static struct uart_amba_port *amba_ports[UART_NR]; #ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE @@ -1994,7 +2061,7 @@ 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 status, old_cr, new_cr; + unsigned int status, old_cr = 0, new_cr; unsigned long flags; int locked = 1; @@ -2017,10 +2084,12 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) /* * First save the CR then disable the interrupts */ - old_cr = readw(uap->port.membase + UART011_CR); - new_cr = old_cr & ~UART011_CR_CTSEN; - new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE; - writew(new_cr, uap->port.membase + UART011_CR); + if (!uap->vendor->always_enabled) { + old_cr = readw(uap->port.membase + UART011_CR); + new_cr = old_cr & ~UART011_CR_CTSEN; + new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE; + writew(new_cr, uap->port.membase + UART011_CR); + } uart_console_write(&uap->port, s, count, pl011_console_putchar); @@ -2031,7 +2100,8 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) do { status = readw(uap->port.membase + UART01x_FR); } while (status & UART01x_FR_BUSY); - writew(old_cr, uap->port.membase + UART011_CR); + if (!uap->vendor->always_enabled) + writew(old_cr, uap->port.membase + UART011_CR); if (locked) spin_unlock_irqrestore(&uap->port.lock, flags); @@ -2111,10 +2181,15 @@ static int __init pl011_console_setup(struct console *co, char *options) uap->port.uartclk = clk_get_rate(uap->clk); - if (options) - uart_parse_options(options, &baud, &parity, &bits, &flow); - else - pl011_console_get_options(uap, &baud, &parity, &bits); + if (uap->vendor->fixed_options) { + baud = uap->fixed_baud; + } else { + if (options) + uart_parse_options(options, + &baud, &parity, &bits, &flow); + else + pl011_console_get_options(uap, &baud, &parity, &bits); + } return uart_set_options(&uap->port, co, baud, parity, bits, flow); } @@ -2206,97 +2281,126 @@ static int pl011_probe_dt_alias(int index, struct device *dev) return ret; } -static int pl011_probe(struct amba_device *dev, const struct amba_id *id) +/* unregisters the driver also if no more ports are left */ +static void pl011_unregister_port(struct uart_amba_port *uap) { - struct uart_amba_port *uap; - struct vendor_data *vendor = id->data; - void __iomem *base; - int i, ret; + int i; + bool busy = false; + + for (i = 0; i < ARRAY_SIZE(amba_ports); i++) { + if (amba_ports[i] == uap) + amba_ports[i] = NULL; + else if (amba_ports[i]) + busy = true; + } + pl011_dma_remove(uap); + if (!busy) + uart_unregister_driver(&amba_reg); +} + +static int pl011_find_free_port(void) +{ + int i; for (i = 0; i < ARRAY_SIZE(amba_ports); i++) if (amba_ports[i] == NULL) - break; - - if (i == ARRAY_SIZE(amba_ports)) - return -EBUSY; + return i; - uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port), - GFP_KERNEL); - if (uap == NULL) - return -ENOMEM; + return -EBUSY; +} - i = pl011_probe_dt_alias(i, &dev->dev); +static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, + struct resource *mmiobase, int index) +{ + void __iomem *base; - base = devm_ioremap(&dev->dev, dev->res.start, - resource_size(&dev->res)); - if (!base) - return -ENOMEM; + base = devm_ioremap_resource(dev, mmiobase); + if (IS_ERR(base)) + return PTR_ERR(base); - uap->clk = devm_clk_get(&dev->dev, NULL); - if (IS_ERR(uap->clk)) - return PTR_ERR(uap->clk); + index = pl011_probe_dt_alias(index, dev); - uap->vendor = vendor; - uap->lcrh_rx = vendor->lcrh_rx; - uap->lcrh_tx = vendor->lcrh_tx; uap->old_cr = 0; - uap->fifosize = vendor->get_fifosize(dev); - uap->port.dev = &dev->dev; - uap->port.mapbase = dev->res.start; + uap->port.dev = dev; + uap->port.mapbase = mmiobase->start; uap->port.membase = base; uap->port.iotype = UPIO_MEM; - uap->port.irq = dev->irq[0]; uap->port.fifosize = uap->fifosize; - uap->port.ops = &amba_pl011_pops; uap->port.flags = UPF_BOOT_AUTOCONF; - uap->port.line = i; - INIT_DELAYED_WORK(&uap->tx_softirq_work, pl011_tx_softirq); + uap->port.line = index; - /* Ensure interrupts from this UART are masked and cleared */ - writew(0, uap->port.membase + UART011_IMSC); - writew(0xffff, uap->port.membase + UART011_ICR); + amba_ports[index] = uap; - snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); + return 0; +} - amba_ports[i] = uap; +static int pl011_register_port(struct uart_amba_port *uap) +{ + int ret; - amba_set_drvdata(dev, uap); + /* Ensure interrupts from this UART are masked and cleared */ + writew(0, uap->port.membase + UART011_IMSC); + writew(0xffff, uap->port.membase + UART011_ICR); if (!amba_reg.state) { ret = uart_register_driver(&amba_reg); if (ret < 0) { - dev_err(&dev->dev, + dev_err(uap->port.dev, "Failed to register AMBA-PL011 driver\n"); return ret; } } ret = uart_add_one_port(&amba_reg, &uap->port); - if (ret) { - amba_ports[i] = NULL; - uart_unregister_driver(&amba_reg); - } + if (ret) + pl011_unregister_port(uap); return ret; } +static int pl011_probe(struct amba_device *dev, const struct amba_id *id) +{ + struct uart_amba_port *uap; + struct vendor_data *vendor = id->data; + int portnr, ret; + + portnr = pl011_find_free_port(); + if (portnr < 0) + return portnr; + + uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port), + GFP_KERNEL); + if (!uap) + return -ENOMEM; + + uap->clk = devm_clk_get(&dev->dev, NULL); + if (IS_ERR(uap->clk)) + return PTR_ERR(uap->clk); + + uap->vendor = vendor; + uap->lcrh_rx = vendor->lcrh_rx; + uap->lcrh_tx = vendor->lcrh_tx; + uap->fifosize = vendor->get_fifosize(dev); + uap->port.irq = dev->irq[0]; + uap->port.ops = &amba_pl011_pops; + + snprintf(uap->type, sizeof(uap->type), "PL011 rev%u", amba_rev(dev)); + + ret = pl011_setup_port(&dev->dev, uap, &dev->res, portnr); + if (ret) + return ret; + + amba_set_drvdata(dev, uap); + + return pl011_register_port(uap); +} + static int pl011_remove(struct amba_device *dev) { struct uart_amba_port *uap = amba_get_drvdata(dev); - bool busy = false; - int i; uart_remove_one_port(&amba_reg, &uap->port); - - for (i = 0; i < ARRAY_SIZE(amba_ports); i++) - if (amba_ports[i] == uap) - amba_ports[i] = NULL; - else if (amba_ports[i]) - busy = true; - - pl011_dma_remove(uap); - if (!busy) - uart_unregister_driver(&amba_reg); + pl011_unregister_port(uap); return 0; } @@ -2324,6 +2428,86 @@ static int pl011_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pl011_dev_pm_ops, pl011_suspend, pl011_resume); +static int sbsa_uart_probe(struct platform_device *pdev) +{ + struct uart_amba_port *uap; + struct resource *r; + int portnr, ret; + int baudrate; + + /* + * Check the mandatory baud rate parameter in the DT node early + * so that we can easily exit with the error. + */ + if (pdev->dev.of_node) { + struct device_node *np = pdev->dev.of_node; + + ret = of_property_read_u32(np, "current-speed", &baudrate); + if (ret) + return ret; + } else { + baudrate = 115200; + } + + portnr = pl011_find_free_port(); + if (portnr < 0) + return portnr; + + uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port), + GFP_KERNEL); + if (!uap) + return -ENOMEM; + + uap->vendor = &vendor_sbsa; + uap->fifosize = 32; + uap->port.irq = platform_get_irq(pdev, 0); + uap->port.ops = &sbsa_uart_pops; + uap->fixed_baud = baudrate; + + snprintf(uap->type, sizeof(uap->type), "SBSA"); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + ret = pl011_setup_port(&pdev->dev, uap, r, portnr); + if (ret) + return ret; + + platform_set_drvdata(pdev, uap); + + return pl011_register_port(uap); +} + +static int sbsa_uart_remove(struct platform_device *pdev) +{ + struct uart_amba_port *uap = platform_get_drvdata(pdev); + + uart_remove_one_port(&amba_reg, &uap->port); + pl011_unregister_port(uap); + return 0; +} + +static const struct of_device_id sbsa_uart_of_match[] = { + { .compatible = "arm,sbsa-uart", }, + {}, +}; +MODULE_DEVICE_TABLE(of, sbsa_uart_of_match); + +static const struct acpi_device_id sbsa_uart_acpi_match[] = { + { "ARMH0011", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, sbsa_uart_acpi_match); + +static struct platform_driver arm_sbsa_uart_platform_driver = { + .probe = sbsa_uart_probe, + .remove = sbsa_uart_remove, + .driver = { + .name = "sbsa-uart", + .of_match_table = of_match_ptr(sbsa_uart_of_match), + .acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match), + }, +}; + static struct amba_id pl011_ids[] = { { .id = 0x00041011, @@ -2354,11 +2538,14 @@ static int __init pl011_init(void) { printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); + if (platform_driver_register(&arm_sbsa_uart_platform_driver)) + pr_warn("could not register SBSA UART platform driver\n"); return amba_driver_register(&pl011_driver); } static void __exit pl011_exit(void) { + platform_driver_unregister(&arm_sbsa_uart_platform_driver); amba_driver_unregister(&pl011_driver); } diff --git a/kernel/drivers/tty/serial/apbuart.c b/kernel/drivers/tty/serial/apbuart.c index f3af31713..75eb083b3 100644 --- a/kernel/drivers/tty/serial/apbuart.c +++ b/kernel/drivers/tty/serial/apbuart.c @@ -581,6 +581,7 @@ static const struct of_device_id apbuart_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, apbuart_match); static struct platform_driver grlib_apbuart_of_driver = { .probe = apbuart_probe, diff --git a/kernel/drivers/tty/serial/atmel_serial.c b/kernel/drivers/tty/serial/atmel_serial.c index 5ca1dfb05..942945589 100644 --- a/kernel/drivers/tty/serial/atmel_serial.c +++ b/kernel/drivers/tty/serial/atmel_serial.c @@ -56,6 +56,15 @@ /* Revisit: We should calculate this based on the actual port settings */ #define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */ +/* The minium number of data FIFOs should be able to contain */ +#define ATMEL_MIN_FIFO_SIZE 8 +/* + * These two offsets are substracted from the RX FIFO size to define the RTS + * high and low thresholds + */ +#define ATMEL_RTS_HIGH_OFFSET 16 +#define ATMEL_RTS_LOW_OFFSET 20 + #if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif @@ -88,37 +97,6 @@ static void atmel_stop_rx(struct uart_port *port); #define ATMEL_ISR_PASS_LIMIT 256 -/* UART registers. CR is write-only, hence no GET macro */ -#define UART_PUT_CR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_CR) -#define UART_GET_MR(port) __raw_readl((port)->membase + ATMEL_US_MR) -#define UART_PUT_MR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_MR) -#define UART_PUT_IER(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IER) -#define UART_PUT_IDR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IDR) -#define UART_GET_IMR(port) __raw_readl((port)->membase + ATMEL_US_IMR) -#define UART_GET_CSR(port) __raw_readl((port)->membase + ATMEL_US_CSR) -#define UART_GET_CHAR(port) __raw_readl((port)->membase + ATMEL_US_RHR) -#define UART_PUT_CHAR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_THR) -#define UART_GET_BRGR(port) __raw_readl((port)->membase + ATMEL_US_BRGR) -#define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR) -#define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR) -#define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR) -#define UART_GET_IP_NAME(port) __raw_readl((port)->membase + ATMEL_US_NAME) -#define UART_GET_IP_VERSION(port) __raw_readl((port)->membase + ATMEL_US_VERSION) - - /* PDC registers */ -#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) -#define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) - -#define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR) -#define UART_GET_RPR(port) __raw_readl((port)->membase + ATMEL_PDC_RPR) -#define UART_PUT_RCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RCR) -#define UART_PUT_RNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR) -#define UART_PUT_RNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR) - -#define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR) -#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR) -#define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR) - struct atmel_dma_buffer { unsigned char *buf; dma_addr_t dma_addr; @@ -134,6 +112,12 @@ struct atmel_uart_char { #define ATMEL_SERIAL_RINGSIZE 1024 /* + * at91: 6 USARTs and one DBGU port (SAM9260) + * avr32: 4 + */ +#define ATMEL_MAX_UART 7 + +/* * We wrap our port structure around the generic uart_port. */ struct atmel_uart_port { @@ -165,12 +149,17 @@ struct atmel_uart_port { struct tasklet_struct tasklet; unsigned int irq_status; unsigned int irq_status_prev; + unsigned int status_change; + unsigned int tx_len; struct circ_buf rx_ring; struct mctrl_gpios *gpios; int gpio_irq[UART_GPIO_MAX]; unsigned int tx_done_mask; + u32 fifo_size; + u32 rts_high; + u32 rts_low; bool ms_irq_enabled; bool is_usart; /* usart or uart */ struct timer_list uart_timer; /* uart timer */ @@ -211,6 +200,43 @@ to_atmel_uart_port(struct uart_port *uart) return container_of(uart, struct atmel_uart_port, uart); } +static inline u32 atmel_uart_readl(struct uart_port *port, u32 reg) +{ + return __raw_readl(port->membase + reg); +} + +static inline void atmel_uart_writel(struct uart_port *port, u32 reg, u32 value) +{ + __raw_writel(value, port->membase + reg); +} + +#ifdef CONFIG_AVR32 + +/* AVR32 cannot handle 8 or 16bit I/O accesses but only 32bit I/O accesses */ +static inline u8 atmel_uart_read_char(struct uart_port *port) +{ + return __raw_readl(port->membase + ATMEL_US_RHR); +} + +static inline void atmel_uart_write_char(struct uart_port *port, u8 value) +{ + __raw_writel(value, port->membase + ATMEL_US_THR); +} + +#else + +static inline u8 atmel_uart_read_char(struct uart_port *port) +{ + return __raw_readb(port->membase + ATMEL_US_RHR); +} + +static inline void atmel_uart_write_char(struct uart_port *port, u8 value) +{ + __raw_writeb(value, port->membase + ATMEL_US_THR); +} + +#endif + #ifdef CONFIG_SERIAL_ATMEL_PDC static bool atmel_use_pdc_rx(struct uart_port *port) { @@ -256,7 +282,7 @@ static unsigned int atmel_get_lines_status(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned int status, ret = 0; - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); mctrl_gpio_get(atmel_port->gpios, &ret); @@ -303,9 +329,9 @@ static int atmel_config_rs485(struct uart_port *port, unsigned int mode; /* Disable interrupts */ - UART_PUT_IDR(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); - mode = UART_GET_MR(port); + mode = atmel_uart_readl(port, ATMEL_US_MR); /* Resetting serial mode to RS232 (0x0) */ mode &= ~ATMEL_US_USMODE; @@ -315,7 +341,8 @@ static int atmel_config_rs485(struct uart_port *port, if (rs485conf->flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; - UART_PUT_TTGR(port, rs485conf->delay_rts_after_send); + atmel_uart_writel(port, ATMEL_US_TTGR, + rs485conf->delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } else { dev_dbg(port->dev, "Setting UART to RS232\n"); @@ -325,10 +352,10 @@ static int atmel_config_rs485(struct uart_port *port, else atmel_port->tx_done_mask = ATMEL_US_TXRDY; } - UART_PUT_MR(port, mode); + atmel_uart_writel(port, ATMEL_US_MR, mode); /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); return 0; } @@ -338,7 +365,9 @@ static int atmel_config_rs485(struct uart_port *port, */ static u_int atmel_tx_empty(struct uart_port *port) { - return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0; + return (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXEMPTY) ? + TIOCSER_TEMT : + 0; } /* @@ -347,13 +376,14 @@ static u_int atmel_tx_empty(struct uart_port *port) static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) { unsigned int control = 0; - unsigned int mode = UART_GET_MR(port); + unsigned int mode = atmel_uart_readl(port, ATMEL_US_MR); unsigned int rts_paused, rts_ready; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); /* override mode to RS485 if needed, otherwise keep the current mode */ if (port->rs485.flags & SER_RS485_ENABLED) { - UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); + atmel_uart_writel(port, ATMEL_US_TTGR, + port->rs485.delay_rts_after_send); mode &= ~ATMEL_US_USMODE; mode |= ATMEL_US_USMODE_RS485; } @@ -383,7 +413,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) else control |= ATMEL_US_DTRDIS; - UART_PUT_CR(port, control); + atmel_uart_writel(port, ATMEL_US_CR, control); mctrl_gpio_set(atmel_port->gpios, mctrl); @@ -394,7 +424,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) else mode |= ATMEL_US_CHMODE_NORMAL; - UART_PUT_MR(port, mode); + atmel_uart_writel(port, ATMEL_US_MR, mode); } /* @@ -405,7 +435,7 @@ static u_int atmel_get_mctrl(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned int ret = 0, status; - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); /* * The control signals are active low. @@ -431,10 +461,10 @@ static void atmel_stop_tx(struct uart_port *port) if (atmel_use_pdc_tx(port)) { /* disable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); } /* Disable interrupts */ - UART_PUT_IDR(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); if ((port->rs485.flags & SER_RS485_ENABLED) && !(port->rs485.flags & SER_RS485_RX_DURING_TX)) @@ -449,7 +479,7 @@ static void atmel_start_tx(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (atmel_use_pdc_tx(port)) { - if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN) + if (atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN) /* The transmitter is already running. Yes, we really need this.*/ return; @@ -459,10 +489,10 @@ static void atmel_start_tx(struct uart_port *port) atmel_stop_rx(port); /* re-enable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); } /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); } /* @@ -470,17 +500,19 @@ static void atmel_start_tx(struct uart_port *port) */ static void atmel_start_rx(struct uart_port *port) { - UART_PUT_CR(port, ATMEL_US_RSTSTA); /* reset status and receiver */ + /* reset status and receiver */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); - UART_PUT_CR(port, ATMEL_US_RXEN); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RXEN); if (atmel_use_pdc_rx(port)) { /* enable PDC controller */ - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | - port->read_status_mask); - UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | + port->read_status_mask); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); } else { - UART_PUT_IER(port, ATMEL_US_RXRDY); + atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_RXRDY); } } @@ -489,15 +521,16 @@ static void atmel_start_rx(struct uart_port *port) */ static void atmel_stop_rx(struct uart_port *port) { - UART_PUT_CR(port, ATMEL_US_RXDIS); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RXDIS); if (atmel_use_pdc_rx(port)) { /* disable PDC receive */ - UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS); - UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | - port->read_status_mask); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS); + atmel_uart_writel(port, ATMEL_US_IDR, + ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | + port->read_status_mask); } else { - UART_PUT_IDR(port, ATMEL_US_RXRDY); + atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_RXRDY); } } @@ -537,7 +570,7 @@ static void atmel_enable_ms(struct uart_port *port) else ier |= ATMEL_US_DCDIC; - UART_PUT_IER(port, ier); + atmel_uart_writel(port, ATMEL_US_IER, ier); } /* @@ -576,7 +609,7 @@ static void atmel_disable_ms(struct uart_port *port) else idr |= ATMEL_US_DCDIC; - UART_PUT_IDR(port, idr); + atmel_uart_writel(port, ATMEL_US_IDR, idr); } /* @@ -585,9 +618,11 @@ static void atmel_disable_ms(struct uart_port *port) static void atmel_break_ctl(struct uart_port *port, int break_state) { if (break_state != 0) - UART_PUT_CR(port, ATMEL_US_STTBRK); /* start break */ + /* start break */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTBRK); else - UART_PUT_CR(port, ATMEL_US_STPBRK); /* stop break */ + /* stop break */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STPBRK); } /* @@ -621,7 +656,7 @@ atmel_buffer_rx_char(struct uart_port *port, unsigned int status, static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status) { /* clear error */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); if (status & ATMEL_US_RXBRK) { /* ignore side-effect */ @@ -644,9 +679,9 @@ static void atmel_rx_chars(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned int status, ch; - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); while (status & ATMEL_US_RXRDY) { - ch = UART_GET_CHAR(port); + ch = atmel_uart_read_char(port); /* * note that the error handling code is @@ -657,12 +692,13 @@ static void atmel_rx_chars(struct uart_port *port) || atmel_port->break_active)) { /* clear error */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); if (status & ATMEL_US_RXBRK && !atmel_port->break_active) { atmel_port->break_active = 1; - UART_PUT_IER(port, ATMEL_US_RXBRK); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_RXBRK); } else { /* * This is either the end-of-break @@ -671,14 +707,15 @@ static void atmel_rx_chars(struct uart_port *port) * being set. In both cases, the next * RXBRK will indicate start-of-break. */ - UART_PUT_IDR(port, ATMEL_US_RXBRK); + atmel_uart_writel(port, ATMEL_US_IDR, + ATMEL_US_RXBRK); status &= ~ATMEL_US_RXBRK; atmel_port->break_active = 0; } } atmel_buffer_rx_char(port, status, ch); - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); } tasklet_schedule(&atmel_port->tasklet); @@ -693,16 +730,18 @@ static void atmel_tx_chars(struct uart_port *port) struct circ_buf *xmit = &port->state->xmit; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - if (port->x_char && UART_GET_CSR(port) & atmel_port->tx_done_mask) { - UART_PUT_CHAR(port, port->x_char); + if (port->x_char && + (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask)) { + atmel_uart_write_char(port, port->x_char); port->icount.tx++; port->x_char = 0; } if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return; - while (UART_GET_CSR(port) & atmel_port->tx_done_mask) { - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); + while (atmel_uart_readl(port, ATMEL_US_CSR) & + atmel_port->tx_done_mask) { + atmel_uart_write_char(port, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) @@ -714,7 +753,8 @@ static void atmel_tx_chars(struct uart_port *port) if (!uart_circ_empty(xmit)) /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IER, + atmel_port->tx_done_mask); } static void atmel_complete_tx_dma(void *arg) @@ -729,10 +769,10 @@ static void atmel_complete_tx_dma(void *arg) if (chan) dmaengine_terminate_all(chan); - xmit->tail += sg_dma_len(&atmel_port->sg_tx); + xmit->tail += atmel_port->tx_len; xmit->tail &= UART_XMIT_SIZE - 1; - port->icount.tx += sg_dma_len(&atmel_port->sg_tx); + port->icount.tx += atmel_port->tx_len; spin_lock_irq(&atmel_port->lock_tx); async_tx_ack(atmel_port->desc_tx); @@ -780,7 +820,9 @@ static void atmel_tx_dma(struct uart_port *port) struct circ_buf *xmit = &port->state->xmit; struct dma_chan *chan = atmel_port->chan_tx; struct dma_async_tx_descriptor *desc; - struct scatterlist *sg = &atmel_port->sg_tx; + struct scatterlist sgl[2], *sg, *sg_tx = &atmel_port->sg_tx; + unsigned int tx_len, part1_len, part2_len, sg_len; + dma_addr_t phys_addr; /* Make sure we have an idle channel */ if (atmel_port->desc_tx != NULL) @@ -796,18 +838,46 @@ static void atmel_tx_dma(struct uart_port *port) * Take the port lock to get a * consistent xmit buffer state. */ - sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); - sg_dma_address(sg) = (sg_dma_address(sg) & - ~(UART_XMIT_SIZE - 1)) - + sg->offset; - sg_dma_len(sg) = CIRC_CNT_TO_END(xmit->head, - xmit->tail, - UART_XMIT_SIZE); - BUG_ON(!sg_dma_len(sg)); + tx_len = CIRC_CNT_TO_END(xmit->head, + xmit->tail, + UART_XMIT_SIZE); + + if (atmel_port->fifo_size) { + /* multi data mode */ + part1_len = (tx_len & ~0x3); /* DWORD access */ + part2_len = (tx_len & 0x3); /* BYTE access */ + } else { + /* single data (legacy) mode */ + part1_len = 0; + part2_len = tx_len; /* BYTE access only */ + } + + sg_init_table(sgl, 2); + sg_len = 0; + phys_addr = sg_dma_address(sg_tx) + xmit->tail; + if (part1_len) { + sg = &sgl[sg_len++]; + sg_dma_address(sg) = phys_addr; + sg_dma_len(sg) = part1_len; + + phys_addr += part1_len; + } + + if (part2_len) { + sg = &sgl[sg_len++]; + sg_dma_address(sg) = phys_addr; + sg_dma_len(sg) = part2_len; + } + + /* + * save tx_len so atmel_complete_tx_dma() will increase + * xmit->tail correctly + */ + atmel_port->tx_len = tx_len; desc = dmaengine_prep_slave_sg(chan, - sg, - 1, + sgl, + sg_len, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -816,7 +886,7 @@ static void atmel_tx_dma(struct uart_port *port) return; } - dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); + dma_sync_sg_for_device(port->dev, sg_tx, 1, DMA_TO_DEVICE); atmel_port->desc_tx = desc; desc->callback = atmel_complete_tx_dma; @@ -857,7 +927,7 @@ static int atmel_prepare_tx_dma(struct uart_port *port) sg_set_page(&atmel_port->sg_tx, virt_to_page(port->state->xmit.buf), UART_XMIT_SIZE, - (int)port->state->xmit.buf & ~PAGE_MASK); + (unsigned long)port->state->xmit.buf & ~PAGE_MASK); nent = dma_map_sg(port->dev, &atmel_port->sg_tx, 1, @@ -867,16 +937,18 @@ static int atmel_prepare_tx_dma(struct uart_port *port) dev_dbg(port->dev, "need to release resource of dma\n"); goto chan_err; } else { - dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__, + 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)); + &sg_dma_address(&atmel_port->sg_tx)); } /* Configure the slave DMA */ memset(&config, 0, sizeof(config)); config.direction = DMA_MEM_TO_DEV; - config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + config.dst_addr_width = (atmel_port->fifo_size) ? + DMA_SLAVE_BUSWIDTH_4_BYTES : + DMA_SLAVE_BUSWIDTH_1_BYTE; config.dst_addr = port->mapbase + ATMEL_US_THR; config.dst_maxburst = 1; @@ -934,14 +1006,14 @@ static void atmel_rx_from_dma(struct uart_port *port) /* Reset the UART timeout early so that we don't miss one */ - UART_PUT_CR(port, ATMEL_US_STTTO); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); dmastat = dmaengine_tx_status(chan, atmel_port->cookie_rx, &state); /* Restart a new tasklet if DMA status is error */ if (dmastat == DMA_ERROR) { dev_dbg(port->dev, "Get residue error, restart tasklet\n"); - UART_PUT_IER(port, ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); tasklet_schedule(&atmel_port->tasklet); return; } @@ -1007,7 +1079,7 @@ static void atmel_rx_from_dma(struct uart_port *port) tty_flip_buffer_push(tport); spin_lock(&port->lock); - UART_PUT_IER(port, ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); } static int atmel_prepare_rx_dma(struct uart_port *port) @@ -1037,7 +1109,7 @@ static int atmel_prepare_rx_dma(struct uart_port *port) sg_set_page(&atmel_port->sg_rx, virt_to_page(ring->buf), sizeof(struct atmel_uart_char) * ATMEL_SERIAL_RINGSIZE, - (int)ring->buf & ~PAGE_MASK); + (unsigned long)ring->buf & ~PAGE_MASK); nent = dma_map_sg(port->dev, &atmel_port->sg_rx, 1, @@ -1047,10 +1119,10 @@ static int atmel_prepare_rx_dma(struct uart_port *port) dev_dbg(port->dev, "need to release resource of dma\n"); goto chan_err; } else { - dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__, + 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)); + &sg_dma_address(&atmel_port->sg_rx)); } /* Configure the slave DMA */ @@ -1117,8 +1189,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) * the moment. */ if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { - UART_PUT_IDR(port, (ATMEL_US_ENDRX - | ATMEL_US_TIMEOUT)); + atmel_uart_writel(port, ATMEL_US_IDR, + (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)); tasklet_schedule(&atmel_port->tasklet); } @@ -1129,7 +1201,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) if (atmel_use_dma_rx(port)) { if (pending & ATMEL_US_TIMEOUT) { - UART_PUT_IDR(port, ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IDR, + ATMEL_US_TIMEOUT); tasklet_schedule(&atmel_port->tasklet); } } @@ -1142,8 +1215,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) * End of break detected. If it came along with a * character, atmel_rx_chars will handle it. */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, ATMEL_US_RXBRK); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); + atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_RXBRK); atmel_port->break_active = 0; } } @@ -1158,7 +1231,8 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending) if (pending & atmel_port->tx_done_mask) { /* Either PDC or interrupt transmission */ - UART_PUT_IDR(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IDR, + atmel_port->tx_done_mask); tasklet_schedule(&atmel_port->tasklet); } } @@ -1175,6 +1249,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending, if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC)) { atmel_port->irq_status = status; + atmel_port->status_change = atmel_port->irq_status ^ + atmel_port->irq_status_prev; + atmel_port->irq_status_prev = status; tasklet_schedule(&atmel_port->tasklet); } } @@ -1193,7 +1270,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) do { status = atmel_get_lines_status(port); - mask = UART_GET_IMR(port); + mask = atmel_uart_readl(port, ATMEL_US_IMR); pending = status & mask; if (!gpio_handled) { /* @@ -1219,7 +1296,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) if (atmel_port->suspended) { atmel_port->pending |= pending; atmel_port->pending_status = status; - UART_PUT_IDR(port, mask); + atmel_uart_writel(port, ATMEL_US_IDR, mask); pm_system_wakeup(); break; } @@ -1256,7 +1333,7 @@ static void atmel_tx_pdc(struct uart_port *port) int count; /* nothing left to transmit? */ - if (UART_GET_TCR(port)) + if (atmel_uart_readl(port, ATMEL_PDC_TCR)) return; xmit->tail += pdc->ofs; @@ -1268,7 +1345,7 @@ static void atmel_tx_pdc(struct uart_port *port) /* more to transmit - setup next transfer */ /* disable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { dma_sync_single_for_device(port->dev, @@ -1279,12 +1356,14 @@ static void atmel_tx_pdc(struct uart_port *port) count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); pdc->ofs = count; - UART_PUT_TPR(port, pdc->dma_addr + xmit->tail); - UART_PUT_TCR(port, count); + atmel_uart_writel(port, ATMEL_PDC_TPR, + pdc->dma_addr + xmit->tail); + atmel_uart_writel(port, ATMEL_PDC_TCR, count); /* re-enable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IER, + atmel_port->tx_done_mask); } else { if ((port->rs485.flags & SER_RS485_ENABLED) && !(port->rs485.flags & SER_RS485_RX_DURING_TX)) { @@ -1410,10 +1489,10 @@ static void atmel_rx_from_pdc(struct uart_port *port) do { /* Reset the UART timeout early so that we don't miss one */ - UART_PUT_CR(port, ATMEL_US_STTTO); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); pdc = &atmel_port->pdc_rx[rx_idx]; - head = UART_GET_RPR(port) - pdc->dma_addr; + head = atmel_uart_readl(port, ATMEL_PDC_RPR) - pdc->dma_addr; tail = pdc->ofs; /* If the PDC has switched buffers, RPR won't contain @@ -1456,8 +1535,8 @@ static void atmel_rx_from_pdc(struct uart_port *port) */ if (head >= pdc->dma_size) { pdc->ofs = 0; - UART_PUT_RNPR(port, pdc->dma_addr); - UART_PUT_RNCR(port, pdc->dma_size); + atmel_uart_writel(port, ATMEL_PDC_RNPR, pdc->dma_addr); + atmel_uart_writel(port, ATMEL_PDC_RNCR, pdc->dma_size); rx_idx = !rx_idx; atmel_port->pdc_rx_idx = rx_idx; @@ -1472,7 +1551,8 @@ static void atmel_rx_from_pdc(struct uart_port *port) tty_flip_buffer_push(tport); spin_lock(&port->lock); - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); } static int atmel_prepare_rx_pdc(struct uart_port *port) @@ -1505,11 +1585,12 @@ static int atmel_prepare_rx_pdc(struct uart_port *port) atmel_port->pdc_rx_idx = 0; - UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr); - UART_PUT_RCR(port, PDC_BUFFER_SIZE); + atmel_uart_writel(port, ATMEL_PDC_RPR, atmel_port->pdc_rx[0].dma_addr); + atmel_uart_writel(port, ATMEL_PDC_RCR, PDC_BUFFER_SIZE); - UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr); - UART_PUT_RNCR(port, PDC_BUFFER_SIZE); + atmel_uart_writel(port, ATMEL_PDC_RNPR, + atmel_port->pdc_rx[1].dma_addr); + atmel_uart_writel(port, ATMEL_PDC_RNCR, PDC_BUFFER_SIZE); return 0; } @@ -1521,17 +1602,14 @@ static void atmel_tasklet_func(unsigned long data) { struct uart_port *port = (struct uart_port *)data; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - unsigned int status; - unsigned int status_change; + unsigned int status = atmel_port->irq_status; + unsigned int status_change = atmel_port->status_change; /* The interrupt handler does not take the lock */ spin_lock(&port->lock); atmel_port->schedule_tx(port); - status = atmel_port->irq_status; - status_change = status ^ atmel_port->irq_status_prev; - if (status_change & (ATMEL_US_RI | ATMEL_US_DSR | ATMEL_US_DCD | ATMEL_US_CTS)) { /* TODO: All reads to CSR will clear these interrupts! */ @@ -1546,7 +1624,7 @@ static void atmel_tasklet_func(unsigned long data) wake_up_interruptible(&port->state->port.delta_msr_wait); - atmel_port->irq_status_prev = status; + atmel_port->status_change = 0; } atmel_port->schedule_rx(port); @@ -1604,15 +1682,15 @@ static void atmel_init_rs485(struct uart_port *port, struct atmel_uart_data *pdata = dev_get_platdata(&pdev->dev); if (np) { + struct serial_rs485 *rs485conf = &port->rs485; u32 rs485_delay[2]; /* rs485 properties */ if (of_property_read_u32_array(np, "rs485-rts-delay", rs485_delay, 2) == 0) { - struct serial_rs485 *rs485conf = &port->rs485; - rs485conf->delay_rts_before_send = rs485_delay[0]; rs485conf->delay_rts_after_send = rs485_delay[1]; rs485conf->flags = 0; + } if (of_get_property(np, "rs485-rx-during-tx", NULL)) rs485conf->flags |= SER_RS485_RX_DURING_TX; @@ -1620,7 +1698,6 @@ static void atmel_init_rs485(struct uart_port *port, if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL)) rs485conf->flags |= SER_RS485_ENABLED; - } } else { port->rs485 = pdata->rs485; } @@ -1666,7 +1743,7 @@ static void atmel_set_ops(struct uart_port *port) static void atmel_get_ip_name(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - int name = UART_GET_IP_NAME(port); + int name = atmel_uart_readl(port, ATMEL_US_NAME); u32 version; int usart, uart; /* usart and uart ascii */ @@ -1683,7 +1760,7 @@ static void atmel_get_ip_name(struct uart_port *port) atmel_port->is_usart = false; } else { /* fallback for older SoCs: use version field */ - version = UART_GET_IP_VERSION(port); + version = atmel_uart_readl(port, ATMEL_US_VERSION); switch (version) { case 0x302: case 0x10213: @@ -1755,7 +1832,7 @@ static int atmel_startup(struct uart_port *port) * request_irq() is called we could get stuck trying to * handle an unexpected interrupt */ - UART_PUT_IDR(port, -1); + atmel_uart_writel(port, ATMEL_US_IDR, -1); atmel_port->ms_irq_enabled = false; /* @@ -1796,6 +1873,32 @@ static int atmel_startup(struct uart_port *port) atmel_set_ops(port); } + /* + * Enable FIFO when available + */ + if (atmel_port->fifo_size) { + unsigned int txrdym = ATMEL_US_ONE_DATA; + unsigned int rxrdym = ATMEL_US_ONE_DATA; + unsigned int fmr; + + atmel_uart_writel(port, ATMEL_US_CR, + ATMEL_US_FIFOEN | + ATMEL_US_RXFCLR | + ATMEL_US_TXFLCLR); + + if (atmel_use_dma_tx(port)) + txrdym = ATMEL_US_FOUR_DATA; + + fmr = ATMEL_US_TXRDYM(txrdym) | ATMEL_US_RXRDYM(rxrdym); + if (atmel_port->rts_high && + atmel_port->rts_low) + fmr |= ATMEL_US_FRTSC | + ATMEL_US_RXFTHRES(atmel_port->rts_high) | + ATMEL_US_RXFTHRES2(atmel_port->rts_low); + + atmel_uart_writel(port, ATMEL_US_FMR, fmr); + } + /* Save current CSR for comparison in atmel_tasklet_func() */ atmel_port->irq_status_prev = atmel_get_lines_status(port); atmel_port->irq_status = atmel_port->irq_status_prev; @@ -1803,9 +1906,9 @@ static int atmel_startup(struct uart_port *port) /* * Finally, enable the serial port */ - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); /* enable xmit & rcvr */ - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); setup_timer(&atmel_port->uart_timer, atmel_uart_timer_callback, @@ -1818,13 +1921,14 @@ static int atmel_startup(struct uart_port *port) jiffies + uart_poll_timeout(port)); /* set USART timeout */ } else { - UART_PUT_RTOR(port, PDC_RX_TIMEOUT); - UART_PUT_CR(port, ATMEL_US_STTTO); + atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); } /* enable PDC controller */ - UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); } else if (atmel_use_dma_rx(port)) { /* set UART timeout */ if (!atmel_port->is_usart) { @@ -1832,14 +1936,15 @@ static int atmel_startup(struct uart_port *port) jiffies + uart_poll_timeout(port)); /* set USART timeout */ } else { - UART_PUT_RTOR(port, PDC_RX_TIMEOUT); - UART_PUT_CR(port, ATMEL_US_STTTO); + atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); - UART_PUT_IER(port, ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_TIMEOUT); } } else { /* enable receive only */ - UART_PUT_IER(port, ATMEL_US_RXRDY); + atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_RXRDY); } return 0; @@ -1859,7 +1964,7 @@ static void atmel_flush_buffer(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (atmel_use_pdc_tx(port)) { - UART_PUT_TCR(port, 0); + atmel_uart_writel(port, ATMEL_PDC_TCR, 0); atmel_port->pdc_tx.ofs = 0; } } @@ -1891,8 +1996,8 @@ static void atmel_shutdown(struct uart_port *port) atmel_stop_rx(port); atmel_stop_tx(port); - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, -1); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); + atmel_uart_writel(port, ATMEL_US_IDR, -1); /* @@ -1937,12 +2042,12 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, clk_prepare_enable(atmel_port->clk); /* re-enable interrupts if we disabled some on suspend */ - UART_PUT_IER(port, atmel_port->backup_imr); + atmel_uart_writel(port, ATMEL_US_IER, atmel_port->backup_imr); break; case 3: /* Back up the interrupt mask and disable all interrupts */ - atmel_port->backup_imr = UART_GET_IMR(port); - UART_PUT_IDR(port, -1); + atmel_port->backup_imr = atmel_uart_readl(port, ATMEL_US_IMR); + atmel_uart_writel(port, ATMEL_US_IDR, -1); /* * Disable the peripheral clock for this serial port. @@ -1965,7 +2070,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int old_mode, mode, imr, quot, baud; /* save the current mode register */ - mode = old_mode = UART_GET_MR(port); + mode = old_mode = atmel_uart_readl(port, ATMEL_US_MR); /* reset the mode, clock divisor, parity, stop bits and data size */ mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | @@ -2024,7 +2129,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, if (atmel_use_pdc_rx(port)) /* need to enable error interrupts */ - UART_PUT_IER(port, port->read_status_mask); + atmel_uart_writel(port, ATMEL_US_IER, port->read_status_mask); /* * Characters to ignore @@ -2051,15 +2156,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, * transmitter is empty if requested by the caller, so there's * no need to wait for it here. */ - imr = UART_GET_IMR(port); - UART_PUT_IDR(port, -1); + imr = atmel_uart_readl(port, ATMEL_US_IMR); + atmel_uart_writel(port, ATMEL_US_IDR, -1); /* disable receiver and transmitter */ - UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXDIS); /* mode */ if (port->rs485.flags & SER_RS485_ENABLED) { - UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); + atmel_uart_writel(port, ATMEL_US_TTGR, + port->rs485.delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } else if (termios->c_cflag & CRTSCTS) { /* RS232 with hardware handshake (RTS/CTS) */ @@ -2070,7 +2176,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, } /* set the mode, clock divisor, parity, stop bits and data size */ - UART_PUT_MR(port, mode); + atmel_uart_writel(port, ATMEL_US_MR, mode); /* * when switching the mode, set the RTS line state according to the @@ -2087,16 +2193,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, rts_state = ATMEL_US_RTSEN; } - UART_PUT_CR(port, rts_state); + atmel_uart_writel(port, ATMEL_US_CR, rts_state); } /* set the baud rate */ - UART_PUT_BRGR(port, quot); - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + atmel_uart_writel(port, ATMEL_US_BRGR, quot); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); /* restore interrupts */ - UART_PUT_IER(port, imr); + atmel_uart_writel(port, ATMEL_US_IER, imr); /* CTS flow-control and modem-status interrupts */ if (UART_ENABLE_MS(port, termios->c_cflag)) @@ -2195,7 +2301,7 @@ static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser) ret = -EINVAL; if (port->uartclk / 16 != ser->baud_base) ret = -EINVAL; - if ((void *)port->mapbase != ser->iomem_base) + if (port->mapbase != (unsigned long)ser->iomem_base) ret = -EINVAL; if (port->iobase != ser->port) ret = -EINVAL; @@ -2207,18 +2313,18 @@ static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser) #ifdef CONFIG_CONSOLE_POLL static int atmel_poll_get_char(struct uart_port *port) { - while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY)) + while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_RXRDY)) cpu_relax(); - return UART_GET_CHAR(port); + return atmel_uart_read_char(port); } static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) { - while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) + while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - UART_PUT_CHAR(port, ch); + atmel_uart_write_char(port, ch); } #endif @@ -2323,9 +2429,9 @@ struct platform_device *atmel_default_console_device; /* the serial console devi #ifdef CONFIG_SERIAL_ATMEL_CONSOLE static void atmel_console_putchar(struct uart_port *port, int ch) { - while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) + while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - UART_PUT_CHAR(port, ch); + atmel_uart_write_char(port, ch); } /* @@ -2341,12 +2447,13 @@ static void atmel_console_write(struct console *co, const char *s, u_int count) /* * First, save IMR and then disable interrupts */ - imr = UART_GET_IMR(port); - UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask); + imr = atmel_uart_readl(port, ATMEL_US_IMR); + atmel_uart_writel(port, ATMEL_US_IDR, + ATMEL_US_RXRDY | atmel_port->tx_done_mask); /* Store PDC transmit status and disable it */ - pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN; - UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + pdc_tx = atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN; + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); uart_console_write(port, s, count, atmel_console_putchar); @@ -2355,15 +2462,15 @@ static void atmel_console_write(struct console *co, const char *s, u_int count) * and restore IMR */ do { - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); } while (!(status & ATMEL_US_TXRDY)); /* Restore PDC transmit status */ if (pdc_tx) - UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); /* set interrupts back the way they were */ - UART_PUT_IER(port, imr); + atmel_uart_writel(port, ATMEL_US_IER, imr); } /* @@ -2379,17 +2486,17 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud, * If the baud rate generator isn't running, the port wasn't * initialized by the boot loader. */ - quot = UART_GET_BRGR(port) & ATMEL_US_CD; + quot = atmel_uart_readl(port, ATMEL_US_BRGR) & ATMEL_US_CD; if (!quot) return; - mr = UART_GET_MR(port) & ATMEL_US_CHRL; + mr = atmel_uart_readl(port, ATMEL_US_MR) & ATMEL_US_CHRL; if (mr == ATMEL_US_CHRL_8) *bits = 8; else *bits = 7; - mr = UART_GET_MR(port) & ATMEL_US_PAR; + mr = atmel_uart_readl(port, ATMEL_US_MR) & ATMEL_US_PAR; if (mr == ATMEL_US_PAR_EVEN) *parity = 'e'; else if (mr == ATMEL_US_PAR_ODD) @@ -2422,9 +2529,9 @@ static int __init atmel_console_setup(struct console *co, char *options) if (ret) return ret; - UART_PUT_IDR(port, -1); - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + atmel_uart_writel(port, ATMEL_US_IDR, -1); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -2531,7 +2638,8 @@ static int atmel_serial_suspend(struct platform_device *pdev, if (atmel_is_console_port(port) && console_suspend_enabled) { /* Drain the TX shifter */ - while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) + while (!(atmel_uart_readl(port, ATMEL_US_CSR) & + ATMEL_US_TXEMPTY)) cpu_relax(); } @@ -2583,7 +2691,7 @@ static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev) enum mctrl_gpio_idx i; struct gpio_desc *gpiod; - p->gpios = mctrl_gpio_init(dev, 0); + p->gpios = mctrl_gpio_init_noauto(dev, 0); if (IS_ERR(p->gpios)) return PTR_ERR(p->gpios); @@ -2598,6 +2706,48 @@ static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev) return 0; } +static void atmel_serial_probe_fifos(struct atmel_uart_port *port, + struct platform_device *pdev) +{ + port->fifo_size = 0; + port->rts_low = 0; + port->rts_high = 0; + + if (of_property_read_u32(pdev->dev.of_node, + "atmel,fifo-size", + &port->fifo_size)) + return; + + if (!port->fifo_size) + return; + + if (port->fifo_size < ATMEL_MIN_FIFO_SIZE) { + port->fifo_size = 0; + dev_err(&pdev->dev, "Invalid FIFO size\n"); + return; + } + + /* + * 0 <= rts_low <= rts_high <= fifo_size + * Once their CTS line asserted by the remote peer, some x86 UARTs tend + * to flush their internal TX FIFO, commonly up to 16 data, before + * actually stopping to send new data. So we try to set the RTS High + * Threshold to a reasonably high value respecting this 16 data + * empirical rule when possible. + */ + port->rts_high = max_t(int, port->fifo_size >> 1, + port->fifo_size - ATMEL_RTS_HIGH_OFFSET); + port->rts_low = max_t(int, port->fifo_size >> 2, + port->fifo_size - ATMEL_RTS_LOW_OFFSET); + + dev_info(&pdev->dev, "Using FIFO (%u data)\n", + port->fifo_size); + dev_dbg(&pdev->dev, "RTS High Threshold : %2u data\n", + port->rts_high); + dev_dbg(&pdev->dev, "RTS Low Threshold : %2u data\n", + port->rts_low); +} + static int atmel_serial_probe(struct platform_device *pdev) { struct atmel_uart_port *port; @@ -2634,13 +2784,14 @@ static int atmel_serial_probe(struct platform_device *pdev) port = &atmel_ports[ret]; port->backup_imr = 0; port->uart.line = ret; + atmel_serial_probe_fifos(port, pdev); spin_lock_init(&port->lock_suspended); ret = atmel_init_gpios(port, &pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "Failed to initialize GPIOs."); - goto err; + goto err_clear_bit; } ret = atmel_init_port(port, pdev); @@ -2683,8 +2834,9 @@ static int atmel_serial_probe(struct platform_device *pdev) clk_prepare_enable(port->clk); if (rs485_enabled) { - UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL); - UART_PUT_CR(&port->uart, ATMEL_US_RTSEN); + atmel_uart_writel(&port->uart, ATMEL_US_MR, + ATMEL_US_USMODE_NORMAL); + atmel_uart_writel(&port->uart, ATMEL_US_CR, ATMEL_US_RTSEN); } /* diff --git a/kernel/drivers/tty/serial/bcm63xx_uart.c b/kernel/drivers/tty/serial/bcm63xx_uart.c index 681e0f3d5..a1c0a89d9 100644 --- a/kernel/drivers/tty/serial/bcm63xx_uart.c +++ b/kernel/drivers/tty/serial/bcm63xx_uart.c @@ -474,7 +474,7 @@ static int bcm_uart_startup(struct uart_port *port) /* register irq and enable rx interrupts */ ret = request_irq(port->irq, bcm_uart_interrupt, 0, - bcm_uart_type(port), port); + dev_name(port->dev), port); if (ret) return ret; bcm_uart_writel(port, UART_RX_INT_MASK, UART_IR_REG); diff --git a/kernel/drivers/tty/serial/bfin_uart.c b/kernel/drivers/tty/serial/bfin_uart.c index 155781ece..ae3cf94b1 100644 --- a/kernel/drivers/tty/serial/bfin_uart.c +++ b/kernel/drivers/tty/serial/bfin_uart.c @@ -74,8 +74,8 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart); static void bfin_serial_reset_irda(struct uart_port *port); -#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +#if defined(SERIAL_BFIN_CTSRTS) || \ + defined(SERIAL_BFIN_HARD_CTSRTS) static unsigned int bfin_serial_get_mctrl(struct uart_port *port) { struct bfin_serial_port *uart = (struct bfin_serial_port *)port; @@ -110,7 +110,7 @@ static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id) struct bfin_serial_port *uart = dev_id; struct uart_port *uport = &uart->port; unsigned int status = bfin_serial_get_mctrl(uport); -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS +#ifdef SERIAL_BFIN_HARD_CTSRTS UART_CLEAR_SCTS(uart); if (uport->hw_stopped) { @@ -700,7 +700,7 @@ static int bfin_serial_startup(struct uart_port *port) # endif #endif -#ifdef CONFIG_SERIAL_BFIN_CTSRTS +#ifdef SERIAL_BFIN_CTSRTS if (uart->cts_pin >= 0) { if (request_irq(gpio_to_irq(uart->cts_pin), bfin_serial_mctrl_cts_int, @@ -718,7 +718,7 @@ static int bfin_serial_startup(struct uart_port *port) gpio_direction_output(uart->rts_pin, 0); } #endif -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS +#ifdef SERIAL_BFIN_HARD_CTSRTS if (uart->cts_pin >= 0) { if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int, 0, "BFIN_UART_MODEM_STATUS", uart)) { @@ -766,13 +766,13 @@ static void bfin_serial_shutdown(struct uart_port *port) free_irq(uart->tx_irq, uart); #endif -#ifdef CONFIG_SERIAL_BFIN_CTSRTS +#ifdef SERIAL_BFIN_CTSRTS if (uart->cts_pin >= 0) free_irq(gpio_to_irq(uart->cts_pin), uart); if (uart->rts_pin >= 0) gpio_free(uart->rts_pin); #endif -#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS +#ifdef SERIAL_BFIN_HARD_CTSRTS if (uart->cts_pin >= 0) free_irq(uart->status_irq, uart); #endif @@ -788,7 +788,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int ier, lcr = 0; unsigned long timeout; -#ifdef CONFIG_SERIAL_BFIN_CTSRTS +#ifdef SERIAL_BFIN_CTSRTS if (old == NULL && uart->cts_pin != -1) termios->c_cflag |= CRTSCTS; else if (uart->cts_pin == -1) @@ -1110,8 +1110,8 @@ bfin_serial_console_setup(struct console *co, char *options) int baud = 57600; int bits = 8; int parity = 'n'; -# if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +# if defined(SERIAL_BFIN_CTSRTS) || \ + defined(SERIAL_BFIN_HARD_CTSRTS) int flow = 'r'; # else int flow = 'n'; @@ -1322,8 +1322,8 @@ static int bfin_serial_probe(struct platform_device *pdev) init_timer(&(uart->rx_dma_timer)); #endif -#if defined(CONFIG_SERIAL_BFIN_CTSRTS) || \ - defined(CONFIG_SERIAL_BFIN_HARD_CTSRTS) +#if defined(SERIAL_BFIN_CTSRTS) || \ + defined(SERIAL_BFIN_HARD_CTSRTS) res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (res == NULL) uart->cts_pin = -1; diff --git a/kernel/drivers/tty/serial/clps711x.c b/kernel/drivers/tty/serial/clps711x.c index d5d2dd7c7..b3a4e0cdd 100644 --- a/kernel/drivers/tty/serial/clps711x.c +++ b/kernel/drivers/tty/serial/clps711x.c @@ -500,7 +500,7 @@ static int uart_clps711x_probe(struct platform_device *pdev) platform_set_drvdata(pdev, s); - s->gpios = mctrl_gpio_init(&pdev->dev, 0); + s->gpios = mctrl_gpio_init_noauto(&pdev->dev, 0); if (IS_ERR(s->gpios)) return PTR_ERR(s->gpios); diff --git a/kernel/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/kernel/drivers/tty/serial/cpm_uart/cpm_uart_core.c index 08431adea..d3e3d42c0 100644 --- a/kernel/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/kernel/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -1450,6 +1450,7 @@ static const struct of_device_id cpm_uart_match[] = { }, {} }; +MODULE_DEVICE_TABLE(of, cpm_uart_match); static struct platform_driver cpm_uart_driver = { .driver = { diff --git a/kernel/drivers/tty/serial/crisv10.c b/kernel/drivers/tty/serial/crisv10.c index 0c1825b0b..f13f2ebd2 100644 --- a/kernel/drivers/tty/serial/crisv10.c +++ b/kernel/drivers/tty/serial/crisv10.c @@ -56,10 +56,6 @@ static char *serial_version = "$Revision: 1.25 $"; #error "RX_TIMEOUT_TICKS == 0 not allowed, use 1" #endif -#if defined(CONFIG_ETRAX_RS485_ON_PA) && defined(CONFIG_ETRAX_RS485_ON_PORT_G) -#error "Disable either CONFIG_ETRAX_RS485_ON_PA or CONFIG_ETRAX_RS485_ON_PORT_G" -#endif - /* * All of the compatibilty code so we can compile serial.c against * older kernels is hidden in serial_compat.h @@ -455,30 +451,6 @@ static struct e100_serial rs_table[] = { static struct fast_timer fast_timers[NR_PORTS]; #endif -#ifdef CONFIG_ETRAX_SERIAL_PROC_ENTRY -#define PROCSTAT(x) x -struct ser_statistics_type { - int overrun_cnt; - int early_errors_cnt; - int ser_ints_ok_cnt; - int errors_cnt; - unsigned long int processing_flip; - unsigned long processing_flip_still_room; - unsigned long int timeout_flush_cnt; - int rx_dma_ints; - int tx_dma_ints; - int rx_tot; - int tx_tot; -}; - -static struct ser_statistics_type ser_stat[NR_PORTS]; - -#else - -#define PROCSTAT(x) - -#endif /* CONFIG_ETRAX_SERIAL_PROC_ENTRY */ - /* RS-485 */ #if defined(CONFIG_ETRAX_RS485) #ifdef CONFIG_ETRAX_FAST_TIMER @@ -487,9 +459,6 @@ static struct fast_timer fast_timers_rs485[NR_PORTS]; #if defined(CONFIG_ETRAX_RS485_ON_PA) static int rs485_pa_bit = CONFIG_ETRAX_RS485_ON_PA_BIT; #endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) -static int rs485_port_g_bit = CONFIG_ETRAX_RS485_ON_PORT_G_BIT; -#endif #endif /* Info and macros needed for each ports extra control/status signals. */ @@ -739,10 +708,10 @@ static unsigned char dummy_ser[NR_PORTS] = {0xFF, 0xFF, 0xFF,0xFF}; defined(CONFIG_ETRAX_SER1_DTR_RI_DSR_CD_MIXED) || \ defined(CONFIG_ETRAX_SER2_DTR_RI_DSR_CD_MIXED) || \ defined(CONFIG_ETRAX_SER3_DTR_RI_DSR_CD_MIXED) -#define CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED +#define ETRAX_SERX_DTR_RI_DSR_CD_MIXED #endif -#ifdef CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED +#ifdef ETRAX_SERX_DTR_RI_DSR_CD_MIXED /* The pins can be mixed on PA and PB */ #define CONTROL_PINS_PORT_NOT_USED(line) \ &dummy_ser[line], &dummy_ser[line], \ @@ -835,7 +804,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = #endif } }; -#else /* CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ +#else /* ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ /* All pins are on either PA or PB for each serial port */ #define CONTROL_PINS_PORT_NOT_USED(line) \ @@ -917,7 +886,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] = #endif } }; -#endif /* !CONFIG_ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ +#endif /* !ETRAX_SERX_DTR_RI_DSR_CD_MIXED */ #define E100_RTS_MASK 0x20 #define E100_CTS_MASK 0x40 @@ -1367,16 +1336,6 @@ e100_enable_rs485(struct tty_struct *tty, struct serial_rs485 *r) #if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow |= (1 << rs485_pa_bit); #endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - rs485_port_g_bit, 1); -#endif -#if defined(CONFIG_ETRAX_RS485_LTC1387) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 1); - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 1); -#endif info->rs485 = *r; @@ -1676,7 +1635,8 @@ alloc_recv_buffer(unsigned int size) { struct etrax_recv_buffer *buffer; - if (!(buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC))) + buffer = kmalloc(sizeof *buffer + size, GFP_ATOMIC); + if (!buffer) return NULL; buffer->next = NULL; @@ -1712,7 +1672,8 @@ add_char_and_flag(struct e100_serial *info, unsigned char data, unsigned char fl { struct etrax_recv_buffer *buffer; if (info->uses_dma_in) { - if (!(buffer = alloc_recv_buffer(4))) + buffer = alloc_recv_buffer(4); + if (!buffer) return 0; buffer->length = 1; @@ -1750,7 +1711,8 @@ static unsigned int handle_descr_data(struct e100_serial *info, append_recv_buffer(info, buffer); - if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE); + if (!buffer) panic("%s: Failed to allocate memory for receive buffer!\n", __func__); descr->buf = virt_to_phys(buffer->buffer); @@ -1841,7 +1803,6 @@ static void receive_chars_dma(struct e100_serial *info) */ unsigned char data = info->ioport[REG_DATA]; - PROCSTAT(ser_stat[info->line].errors_cnt++); DEBUG_LOG(info->line, "#dERR: s d 0x%04X\n", ((rstat & SER_ERROR_MASK) << 8) | data); @@ -1867,7 +1828,8 @@ static int start_recv_dma(struct e100_serial *info) /* Set up the receiving descriptors */ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { - if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) + buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE); + if (!buffer) panic("%s: Failed to allocate memory for receive buffer!\n", __func__); descr[i].ctrl = d_int; @@ -1943,7 +1905,6 @@ tr_interrupt(int irq, void *dev_id) /* Read jiffies_usec first, * we want this time to be as late as possible */ - PROCSTAT(ser_stat[info->line].tx_dma_ints++); info->last_tx_active_usec = GET_JIFFIES_USEC(); info->last_tx_active = jiffies; transmit_chars_dma(info); @@ -2022,7 +1983,6 @@ static int force_eop_if_needed(struct e100_serial *info) */ if (!info->forced_eop) { info->forced_eop = 1; - PROCSTAT(ser_stat[info->line].timeout_flush_cnt++); TIMERD(DEBUG_LOG(info->line, "timeout EOP %i\n", info->line)); FORCE_EOP(info); } @@ -2374,7 +2334,6 @@ static void handle_ser_rx_interrupt(struct e100_serial *info) DEBUG_LOG(info->line, "#iERR s d %04X\n", ((rstat & SER_ERROR_MASK) << 8) | data); } - PROCSTAT(ser_stat[info->line].early_errors_cnt++); } else { /* It was a valid byte, now let the DMA do the rest */ unsigned long curr_time_u = GET_JIFFIES_USEC(); unsigned long curr_time = jiffies; @@ -2407,7 +2366,6 @@ static void handle_ser_rx_interrupt(struct e100_serial *info) DINTR2(DEBUG_LOG(info->line, "ser_rx OK %d\n", info->line)); info->break_detected_cnt = 0; - PROCSTAT(ser_stat[info->line].ser_ints_ok_cnt++); } /* Restarting the DMA never hurts */ *info->icmdadr = IO_STATE(R_DMA_CH6_CMD, cmd, restart); @@ -2867,19 +2825,6 @@ change_speed(struct e100_serial *info) *R_SERIAL_PRESCALE = divisor; info->baud = SERIAL_PRESCALE_BASE/divisor; } -#ifdef CONFIG_ETRAX_EXTERN_PB6CLK_ENABLED - else if ((info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8 && - info->custom_divisor == 1) || - (info->baud_base==CONFIG_ETRAX_EXTERN_PB6CLK_FREQ && - info->custom_divisor == 8)) { - /* ext_clk selected */ - alt_source = - IO_STATE(R_ALT_SER_BAUDRATE, ser0_rec, extern) | - IO_STATE(R_ALT_SER_BAUDRATE, ser0_tr, extern); - DBAUD(printk("using external baudrate: %lu\n", CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8)); - info->baud = CONFIG_ETRAX_EXTERN_PB6CLK_FREQ/8; - } -#endif else { /* Bad baudbase, we don't support using timer0 @@ -3216,9 +3161,7 @@ rs_throttle(struct tty_struct * tty) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %lu....\n", tty_name(tty, buf), + printk("throttle %s: %lu....\n", tty_name(tty), (unsigned long)tty->ldisc.chars_in_buffer(tty)); #endif DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty))); @@ -3238,9 +3181,7 @@ rs_unthrottle(struct tty_struct * tty) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; #ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %lu....\n", tty_name(tty, buf), + printk("unthrottle %s: %lu....\n", tty_name(tty), (unsigned long)tty->ldisc.chars_in_buffer(tty)); #endif DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty))); @@ -3714,7 +3655,6 @@ rs_close(struct tty_struct *tty, struct file * filp) wake_up_interruptible(&info->port.open_wait); } info->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); - wake_up_interruptible(&info->port.close_wait); local_irq_restore(flags); /* port closed */ @@ -3725,16 +3665,6 @@ rs_close(struct tty_struct *tty, struct file * filp) #if defined(CONFIG_ETRAX_RS485_ON_PA) *R_PORT_PA_DATA = port_pa_data_shadow &= ~(1 << rs485_pa_bit); #endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - rs485_port_g_bit, 0); -#endif -#if defined(CONFIG_ETRAX_RS485_LTC1387) - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_DXEN_PORT_G_BIT, 0); - REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, - CONFIG_ETRAX_RS485_LTC1387_RXEN_PORT_G_BIT, 0); -#endif } #endif @@ -3828,23 +3758,6 @@ block_til_ready(struct tty_struct *tty, struct file * filp, int do_clocal = 0; /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (info->port.flags & ASYNC_CLOSING) { - wait_event_interruptible_tty(tty, info->port.close_wait, - !(info->port.flags & ASYNC_CLOSING)); -#ifdef SERIAL_DO_RESTART - if (info->port.flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ @@ -3894,7 +3807,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp, #endif break; } - if (!(info->port.flags & ASYNC_CLOSING) && do_clocal) + if (do_clocal) /* && (do_clocal || DCD_IS_ASSERTED) */ break; if (signal_pending(current)) { @@ -3964,20 +3877,6 @@ rs_open(struct tty_struct *tty, struct file * filp) info->port.low_latency = !!(info->port.flags & ASYNC_LOW_LATENCY); /* - * If the port is in the middle of closing, bail out now - */ - if (info->port.flags & ASYNC_CLOSING) { - wait_event_interruptible_tty(tty, info->port.close_wait, - !(info->port.flags & ASYNC_CLOSING)); -#ifdef SERIAL_DO_RESTART - return ((info->port.flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif - } - - /* * If DMA is enabled try to allocate the irq's. */ if (info->port.count == 1) { @@ -4263,15 +4162,6 @@ static int __init rs_init(void) return -EBUSY; } #endif -#if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit, - rs485_port_g_bit)) { - printk(KERN_ERR "ETRAX100LX serial: Could not allocate " - "RS485 pin\n"); - put_tty_driver(driver); - return -EBUSY; - } -#endif #endif /* Initialize the tty_driver structure */ diff --git a/kernel/drivers/tty/serial/earlycon.c b/kernel/drivers/tty/serial/earlycon.c index 6dc471e30..b5b2f2be6 100644 --- a/kernel/drivers/tty/serial/earlycon.c +++ b/kernel/drivers/tty/serial/earlycon.c @@ -72,6 +72,7 @@ static int __init parse_options(struct earlycon_device *device, char *options) switch (port->iotype) { case UPIO_MEM32: + case UPIO_MEM32BE: port->regshift = 2; /* fall-through */ case UPIO_MEM: port->mapbase = addr; @@ -90,9 +91,11 @@ static int __init parse_options(struct earlycon_device *device, char *options) strlcpy(device->options, options, length); } - if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32) + if (port->iotype == UPIO_MEM || port->iotype == UPIO_MEM32 || + port->iotype == UPIO_MEM32BE) pr_info("Early serial console at MMIO%s 0x%llx (options '%s')\n", - (port->iotype == UPIO_MEM32) ? "32" : "", + (port->iotype == UPIO_MEM) ? "" : + (port->iotype == UPIO_MEM32) ? "32" : "32be", (unsigned long long)port->mapbase, device->options); else @@ -112,6 +115,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match) if (buf && !parse_options(&early_console_dev, buf)) buf = NULL; + spin_lock_init(&port->lock); port->uartclk = BASE_BAUD * 16; if (port->mapbase) port->membase = earlycon_map(port->mapbase, 64); @@ -133,7 +137,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match) * * Registers the earlycon console matching the earlycon specified * in the param string @buf. Acceptable param strings are of the form - * <name>,io|mmio|mmio32,<addr>,<options> + * <name>,io|mmio|mmio32|mmio32be,<addr>,<options> * <name>,0x<addr>,<options> * <name>,<options> * <name> @@ -199,6 +203,7 @@ int __init of_setup_earlycon(unsigned long addr, int err; struct uart_port *port = &early_console_dev.port; + spin_lock_init(&port->lock); port->iotype = UPIO_MEM; port->mapbase = addr; port->uartclk = BASE_BAUD * 16; diff --git a/kernel/drivers/tty/serial/etraxfs-uart.c b/kernel/drivers/tty/serial/etraxfs-uart.c index a57301a6f..2f80bc7e4 100644 --- a/kernel/drivers/tty/serial/etraxfs-uart.c +++ b/kernel/drivers/tty/serial/etraxfs-uart.c @@ -10,6 +10,8 @@ #include <linux/of_address.h> #include <hwregs/ser_defs.h> +#include "serial_mctrl_gpio.h" + #define DRV_NAME "etraxfs-uart" #define UART_NR CONFIG_ETRAX_SERIAL_PORTS @@ -28,10 +30,7 @@ struct uart_cris_port { void __iomem *regi_ser; - struct gpio_desc *dtr_pin; - struct gpio_desc *dsr_pin; - struct gpio_desc *ri_pin; - struct gpio_desc *cd_pin; + struct mctrl_gpios *gpios; int write_ongoing; }; @@ -112,17 +111,10 @@ cris_console_setup(struct console *co, char *options) return 0; } -static struct tty_driver *cris_console_device(struct console *co, int *index) -{ - struct uart_driver *p = co->data; - *index = co->index; - return p->tty_driver; -} - static struct console cris_console = { .name = "ttyS", .write = cris_console_write, - .device = cris_console_device, + .device = uart_console_device, .setup = cris_console_setup, .flags = CON_PRINTBUFFER, .index = -1, @@ -373,14 +365,6 @@ static void etraxfs_uart_stop_rx(struct uart_port *port) REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl); } -static void etraxfs_uart_enable_ms(struct uart_port *port) -{ -} - -static void check_modem_status(struct uart_cris_port *up) -{ -} - static unsigned int etraxfs_uart_tx_empty(struct uart_port *port) { struct uart_cris_port *up = (struct uart_cris_port *)port; @@ -404,21 +388,9 @@ static unsigned int etraxfs_uart_get_mctrl(struct uart_port *port) ret = 0; if (crisv32_serial_get_rts(up)) ret |= TIOCM_RTS; - /* DTR is active low */ - if (up->dtr_pin && !gpiod_get_raw_value(up->dtr_pin)) - ret |= TIOCM_DTR; - /* CD is active low */ - if (up->cd_pin && !gpiod_get_raw_value(up->cd_pin)) - ret |= TIOCM_CD; - /* RI is active low */ - if (up->ri_pin && !gpiod_get_raw_value(up->ri_pin)) - ret |= TIOCM_RI; - /* DSR is active low */ - if (up->dsr_pin && !gpiod_get_raw_value(up->dsr_pin)) - ret |= TIOCM_DSR; if (crisv32_serial_get_cts(up)) ret |= TIOCM_CTS; - return ret; + return mctrl_gpio_get(up->gpios, &ret); } static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) @@ -426,15 +398,7 @@ static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) struct uart_cris_port *up = (struct uart_cris_port *)port; crisv32_serial_set_rts(up, mctrl & TIOCM_RTS ? 1 : 0, 0); - /* DTR is active low */ - if (up->dtr_pin) - gpiod_set_raw_value(up->dtr_pin, mctrl & TIOCM_DTR ? 0 : 1); - /* RI is active low */ - if (up->ri_pin) - gpiod_set_raw_value(up->ri_pin, mctrl & TIOCM_RNG ? 0 : 1); - /* CD is active low */ - if (up->cd_pin) - gpiod_set_raw_value(up->cd_pin, mctrl & TIOCM_CD ? 0 : 1); + mctrl_gpio_set(up->gpios, mctrl); } static void etraxfs_uart_break_ctl(struct uart_port *port, int break_state) @@ -598,7 +562,6 @@ ser_interrupt(int irq, void *dev_id) receive_chars_no_dma(up); handled = 1; } - check_modem_status(up); if (masked_intr.tr_rdy) { transmit_chars_no_dma(up); @@ -862,7 +825,6 @@ static const struct uart_ops etraxfs_uart_pops = { .start_tx = etraxfs_uart_start_tx, .send_xchar = etraxfs_uart_send_xchar, .stop_rx = etraxfs_uart_stop_rx, - .enable_ms = etraxfs_uart_enable_ms, .break_ctl = etraxfs_uart_break_ctl, .startup = etraxfs_uart_startup, .shutdown = etraxfs_uart_shutdown, @@ -930,11 +892,12 @@ static int etraxfs_uart_probe(struct platform_device *pdev) up->irq = irq_of_parse_and_map(np, 0); up->regi_ser = of_iomap(np, 0); - up->dtr_pin = devm_gpiod_get_optional(&pdev->dev, "dtr"); - up->dsr_pin = devm_gpiod_get_optional(&pdev->dev, "dsr"); - up->ri_pin = devm_gpiod_get_optional(&pdev->dev, "ri"); - up->cd_pin = devm_gpiod_get_optional(&pdev->dev, "cd"); up->port.dev = &pdev->dev; + + up->gpios = mctrl_gpio_init_noauto(&pdev->dev, 0); + if (IS_ERR(up->gpios)) + return PTR_ERR(up->gpios); + cris_serial_port_init(&up->port, dev_id); etraxfs_uart_ports[dev_id] = up; @@ -950,7 +913,7 @@ static int etraxfs_uart_remove(struct platform_device *pdev) port = platform_get_drvdata(pdev); uart_remove_one_port(&etraxfs_uart_driver, port); - etraxfs_uart_ports[pdev->id] = NULL; + etraxfs_uart_ports[port->line] = NULL; return 0; } diff --git a/kernel/drivers/tty/serial/fsl_lpuart.c b/kernel/drivers/tty/serial/fsl_lpuart.c index 08ce76f4f..3d7900337 100644 --- a/kernel/drivers/tty/serial/fsl_lpuart.c +++ b/kernel/drivers/tty/serial/fsl_lpuart.c @@ -1746,6 +1746,45 @@ static struct console lpuart32_console = { .data = &lpuart_reg, }; +static void lpuart_early_write(struct console *con, const char *s, unsigned n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, lpuart_console_putchar); +} + +static void lpuart32_early_write(struct console *con, const char *s, unsigned n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, lpuart32_console_putchar); +} + +static int __init lpuart_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = lpuart_early_write; + return 0; +} + +static int __init lpuart32_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = lpuart32_early_write; + return 0; +} + +OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup); +OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup); +EARLYCON_DECLARE(lpuart, lpuart_early_console_setup); +EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup); + #define LPUART_CONSOLE (&lpuart_console) #define LPUART32_CONSOLE (&lpuart32_console) #else diff --git a/kernel/drivers/tty/serial/icom.c b/kernel/drivers/tty/serial/icom.c index 45fc323b9..ffc7cb258 100644 --- a/kernel/drivers/tty/serial/icom.c +++ b/kernel/drivers/tty/serial/icom.c @@ -1504,7 +1504,8 @@ static int icom_probe(struct pci_dev *dev, return retval; } - if ( (retval = pci_request_regions(dev, "icom"))) { + retval = pci_request_regions(dev, "icom"); + if (retval) { dev_err(&dev->dev, "pci_request_regions FAILED\n"); pci_disable_device(dev); return retval; @@ -1512,7 +1513,8 @@ static int icom_probe(struct pci_dev *dev, pci_set_master(dev); - if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) { + retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg); + if (retval) { dev_err(&dev->dev, "PCI Config read FAILED\n"); return retval; } @@ -1556,9 +1558,8 @@ static int icom_probe(struct pci_dev *dev, } /* save off irq and request irq line */ - if ( (retval = request_irq(dev->irq, icom_interrupt, - IRQF_SHARED, ICOM_DRIVER_NAME, - (void *) icom_adapter))) { + retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter); + if (retval) { goto probe_exit2; } diff --git a/kernel/drivers/tty/serial/ifx6x60.c b/kernel/drivers/tty/serial/ifx6x60.c index 590390970..88246f7e4 100644 --- a/kernel/drivers/tty/serial/ifx6x60.c +++ b/kernel/drivers/tty/serial/ifx6x60.c @@ -1175,7 +1175,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ret = request_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_spi_reset_interrupt, IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, DRVNAME, - (void *)ifx_dev); + ifx_dev); if (ret) { dev_err(&spi->dev, "Unable to get irq %x\n", gpio_to_irq(ifx_dev->gpio.reset_out)); @@ -1185,9 +1185,8 @@ static int ifx_spi_spi_probe(struct spi_device *spi) ret = ifx_spi_reset(ifx_dev); ret = request_irq(gpio_to_irq(ifx_dev->gpio.srdy), - ifx_spi_srdy_interrupt, - IRQF_TRIGGER_RISING, DRVNAME, - (void *)ifx_dev); + ifx_spi_srdy_interrupt, IRQF_TRIGGER_RISING, DRVNAME, + ifx_dev); if (ret) { dev_err(&spi->dev, "Unable to get irq %x", gpio_to_irq(ifx_dev->gpio.srdy)); @@ -1212,7 +1211,7 @@ static int ifx_spi_spi_probe(struct spi_device *spi) return 0; error_ret7: - free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev); + free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev); error_ret6: gpio_free(ifx_dev->gpio.srdy); error_ret5: @@ -1243,8 +1242,8 @@ static int ifx_spi_spi_remove(struct spi_device *spi) /* stop activity */ tasklet_kill(&ifx_dev->io_work_tasklet); /* free irq */ - free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), (void *)ifx_dev); - free_irq(gpio_to_irq(ifx_dev->gpio.srdy), (void *)ifx_dev); + free_irq(gpio_to_irq(ifx_dev->gpio.reset_out), ifx_dev); + free_irq(gpio_to_irq(ifx_dev->gpio.srdy), ifx_dev); gpio_free(ifx_dev->gpio.srdy); gpio_free(ifx_dev->gpio.mrdy); @@ -1363,7 +1362,7 @@ static struct spi_driver ifx_spi_driver = { .driver = { .name = DRVNAME, .pm = &ifx_spi_pm, - .owner = THIS_MODULE}, + }, .probe = ifx_spi_spi_probe, .shutdown = ifx_spi_spi_shutdown, .remove = ifx_spi_spi_remove, @@ -1381,7 +1380,7 @@ static void __exit ifx_spi_exit(void) /* unregister */ tty_unregister_driver(tty_drv); put_tty_driver(tty_drv); - spi_unregister_driver((void *)&ifx_spi_driver); + spi_unregister_driver(&ifx_spi_driver); unregister_reboot_notifier(&ifx_modem_reboot_notifier_block); } @@ -1420,7 +1419,7 @@ static int __init ifx_spi_init(void) goto err_free_tty; } - result = spi_register_driver((void *)&ifx_spi_driver); + result = spi_register_driver(&ifx_spi_driver); if (result) { pr_err("%s: spi_register_driver failed(%d)", DRVNAME, result); @@ -1436,7 +1435,7 @@ static int __init ifx_spi_init(void) return 0; err_unreg_spi: - spi_unregister_driver((void *)&ifx_spi_driver); + spi_unregister_driver(&ifx_spi_driver); err_unreg_tty: tty_unregister_driver(tty_drv); err_free_tty: diff --git a/kernel/drivers/tty/serial/imx.c b/kernel/drivers/tty/serial/imx.c index 01aa52f57..016e4be05 100644 --- a/kernel/drivers/tty/serial/imx.c +++ b/kernel/drivers/tty/serial/imx.c @@ -139,6 +139,7 @@ #define USR1_ESCF (1<<11) /* Escape seq interrupt flag */ #define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ #define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ +#define USR1_AGTIM (1<<8) /* Ageing timer interrupt flag */ #define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ #define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ #define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ @@ -216,6 +217,8 @@ struct imx_port { unsigned int tx_bytes; unsigned int dma_tx_nents; wait_queue_head_t dma_wait; + unsigned int saved_reg[10]; + bool context_saved; }; struct imx_port_ucrs { @@ -239,7 +242,7 @@ static struct imx_uart_data imx_uart_devdata[] = { }, }; -static struct platform_device_id imx_uart_devtype[] = { +static const struct platform_device_id imx_uart_devtype[] = { { .name = "imx1-uart", .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART], @@ -700,7 +703,8 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) if (sport->port.ignore_status_mask & URXD_DUMMY_READ) goto out; - tty_insert_flip_char(port, rx, flg); + if (tty_insert_flip_char(port, rx, flg) == 0) + sport->port.icount.buf_overrun++; } out: @@ -725,11 +729,15 @@ static void imx_dma_rxint(struct imx_port *sport) if ((temp & USR2_RDR) && !sport->dma_is_rxing) { sport->dma_is_rxing = 1; - /* disable the `Recerver Ready Interrrupt` */ + /* disable the receiver ready and aging timer interrupts */ temp = readl(sport->port.membase + UCR1); temp &= ~(UCR1_RRDYEN); writel(temp, sport->port.membase + UCR1); + temp = readl(sport->port.membase + UCR2); + temp &= ~(UCR2_ATEN); + writel(temp, sport->port.membase + UCR2); + /* tell the DMA to receive the data. */ start_rx_dma(sport); } @@ -746,7 +754,7 @@ static irqreturn_t imx_int(int irq, void *dev_id) sts = readl(sport->port.membase + USR1); sts2 = readl(sport->port.membase + USR2); - if (sts & USR1_RRDY) { + if (sts & (USR1_RRDY | USR1_AGTIM)) { if (sport->dma_is_enabled) imx_dma_rxint(sport); else @@ -766,7 +774,6 @@ static irqreturn_t imx_int(int irq, void *dev_id) writel(USR1_AWAKE, sport->port.membase + USR1); if (sts2 & USR2_ORE) { - dev_err(sport->port.dev, "Rx FIFO overrun\n"); sport->port.icount.overrun++; writel(USR2_ORE, sport->port.membase + USR2); } @@ -850,20 +857,6 @@ static void imx_break_ctl(struct uart_port *port, int break_state) spin_unlock_irqrestore(&sport->port.lock, flags); } -#define TXTL 2 /* reset default */ -#define RXTL 1 /* reset default */ - -static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) -{ - unsigned int val; - - /* set receiver / transmitter trigger level */ - val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE); - val |= TXTL << UFCR_TXTL_SHF | RXTL; - writel(val, sport->port.membase + UFCR); - return 0; -} - #define RX_BUF_SIZE (PAGE_SIZE) static void imx_rx_dma_done(struct imx_port *sport) { @@ -872,11 +865,15 @@ static void imx_rx_dma_done(struct imx_port *sport) spin_lock_irqsave(&sport->port.lock, flags); - /* Enable this interrupt when the RXFIFO is empty. */ + /* re-enable interrupts to get notified when new symbols are incoming */ temp = readl(sport->port.membase + UCR1); temp |= UCR1_RRDYEN; writel(temp, sport->port.membase + UCR1); + temp = readl(sport->port.membase + UCR2); + temp |= UCR2_ATEN; + writel(temp, sport->port.membase + UCR2); + sport->dma_is_rxing = 0; /* Is the shutdown waiting for us? */ @@ -887,14 +884,12 @@ static void imx_rx_dma_done(struct imx_port *sport) } /* - * There are three kinds of RX DMA interrupts(such as in the MX6Q): + * There are two kinds of RX DMA interrupts(such as in the MX6Q): * [1] the RX DMA buffer is full. - * [2] the Aging timer expires(wait for 8 bytes long) - * [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN). + * [2] the aging timer expires * - * The [2] is trigger when a character was been sitting in the FIFO - * meanwhile [3] can wait for 32 bytes long when the RX line is - * on IDLE state and RxFIFO is empty. + * Condition [2] is triggered when a character has been sitting in the FIFO + * for at least 8 byte durations. */ static void dma_rx_callback(void *data) { @@ -912,36 +907,32 @@ static void dma_rx_callback(void *data) status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); count = RX_BUF_SIZE - state.residue; - if (readl(sport->port.membase + USR2) & USR2_IDLE) { - /* In condition [3] the SDMA counted up too early */ - count--; - - writel(USR2_IDLE, sport->port.membase + USR2); - } - dev_dbg(sport->port.dev, "We get %d bytes.\n", count); if (count) { - if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) - tty_insert_flip_string(port, sport->rx_buf, count); + if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) { + int bytes = tty_insert_flip_string(port, sport->rx_buf, + count); + + if (bytes != count) + sport->port.icount.buf_overrun++; + } tty_flip_buffer_push(port); + sport->port.icount.rx += count; + } + /* + * Restart RX DMA directly if more data is available in order to skip + * the roundtrip through the IRQ handler. If there is some data already + * in the FIFO, DMA needs to be restarted soon anyways. + * + * Otherwise stop the DMA and reactivate FIFO IRQs to restart DMA once + * data starts to arrive again. + */ + if (readl(sport->port.membase + USR2) & USR2_RDR) start_rx_dma(sport); - } else if (readl(sport->port.membase + USR2) & USR2_RDR) { - /* - * start rx_dma directly once data in RXFIFO, more efficient - * than before: - * 1. call imx_rx_dma_done to stop dma if no data received - * 2. wait next RDR interrupt to start dma transfer. - */ - start_rx_dma(sport); - } else { - /* - * stop dma to prevent too many IDLE event trigged if no data - * in RXFIFO - */ + else imx_rx_dma_done(sport); - } } static int start_rx_dma(struct imx_port *sport) @@ -974,6 +965,22 @@ static int start_rx_dma(struct imx_port *sport) return 0; } +#define TXTL_DEFAULT 2 /* reset default */ +#define RXTL_DEFAULT 1 /* reset default */ +#define TXTL_DMA 8 /* DMA burst setting */ +#define RXTL_DMA 9 /* DMA burst setting */ + +static void imx_setup_ufcr(struct imx_port *sport, + unsigned char txwl, unsigned char rxwl) +{ + unsigned int val; + + /* set receiver / transmitter trigger level */ + val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE); + val |= txwl << UFCR_TXTL_SHF | rxwl; + writel(val, sport->port.membase + UFCR); +} + static void imx_uart_dma_exit(struct imx_port *sport) { if (sport->dma_chan_rx) { @@ -1009,7 +1016,8 @@ static int imx_uart_dma_init(struct imx_port *sport) slave_config.direction = DMA_DEV_TO_MEM; slave_config.src_addr = sport->port.mapbase + URXD0; slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - slave_config.src_maxburst = RXTL; + /* one byte less than the watermark level to enable the aging timer */ + slave_config.src_maxburst = RXTL_DMA - 1; ret = dmaengine_slave_config(sport->dma_chan_rx, &slave_config); if (ret) { dev_err(dev, "error in RX dma configuration.\n"); @@ -1033,7 +1041,7 @@ static int imx_uart_dma_init(struct imx_port *sport) slave_config.direction = DMA_MEM_TO_DEV; slave_config.dst_addr = sport->port.mapbase + URTX0; slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - slave_config.dst_maxburst = TXTL; + slave_config.dst_maxburst = TXTL_DMA; ret = dmaengine_slave_config(sport->dma_chan_tx, &slave_config); if (ret) { dev_err(dev, "error in TX dma configuration."); @@ -1056,15 +1064,14 @@ static void imx_enable_dma(struct imx_port *sport) /* set UCR1 */ temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN | - /* wait for 32 idle frames for IDDMA interrupt */ - UCR1_ICD_REG(3); + temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN; writel(temp, sport->port.membase + UCR1); - /* set UCR4 */ - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_IDDMAEN; - writel(temp, sport->port.membase + UCR4); + temp = readl(sport->port.membase + UCR2); + temp |= UCR2_ATEN; + writel(temp, sport->port.membase + UCR2); + + imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); sport->dma_is_enabled = 1; } @@ -1080,13 +1087,10 @@ static void imx_disable_dma(struct imx_port *sport) /* clear UCR2 */ temp = readl(sport->port.membase + UCR2); - temp &= ~(UCR2_CTSC | UCR2_CTS); + temp &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN); writel(temp, sport->port.membase + UCR2); - /* clear UCR4 */ - temp = readl(sport->port.membase + UCR4); - temp &= ~UCR4_IDDMAEN; - writel(temp, sport->port.membase + UCR4); + imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); sport->dma_is_enabled = 0; } @@ -1109,7 +1113,7 @@ static int imx_startup(struct uart_port *port) return retval; } - imx_setup_ufcr(sport, 0); + imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); /* disable the DREN bit (Data Ready interrupt enable) before * requesting IRQs @@ -1122,6 +1126,12 @@ static int imx_startup(struct uart_port *port) writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); + /* Can we enable the DMA support? */ + if (is_imx6q_uart(sport) && !uart_console(port) && + !sport->dma_is_inited) + imx_uart_dma_init(sport); + + spin_lock_irqsave(&sport->port.lock, flags); /* Reset fifo's and state machines */ i = 100; @@ -1132,14 +1142,15 @@ static int imx_startup(struct uart_port *port) while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) udelay(1); - spin_lock_irqsave(&sport->port.lock, flags); - /* * Finally, clear and enable interrupts */ writel(USR1_RTSD, sport->port.membase + USR1); writel(USR2_ORE, sport->port.membase + USR2); + if (sport->dma_is_inited && !sport->dma_is_enabled) + imx_enable_dma(sport); + temp = readl(sport->port.membase + UCR1); temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; @@ -1273,7 +1284,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; - unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; + unsigned int ucr2, old_ucr1, old_ucr2, baud, quot; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; unsigned int div, ufcr; unsigned long num, denom; @@ -1310,11 +1321,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, } else { ucr2 |= UCR2_CTSC; } - - /* Can we enable the DMA support? */ - if (is_imx6q_uart(sport) && !uart_console(port) - && !sport->dma_is_inited) - imx_uart_dma_init(sport); } else { termios->c_cflag &= ~CRTSCTS; } @@ -1382,10 +1388,10 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, barrier(); /* then, disable everything */ - old_txrxen = readl(sport->port.membase + UCR2); - writel(old_txrxen & ~(UCR2_TXEN | UCR2_RXEN), + old_ucr2 = readl(sport->port.membase + UCR2); + writel(old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN), sport->port.membase + UCR2); - old_txrxen &= (UCR2_TXEN | UCR2_RXEN); + old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN); /* custom-baudrate handling */ div = sport->port.uartclk / (baud * 16); @@ -1426,13 +1432,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, writel(old_ucr1, sport->port.membase + UCR1); /* set the parity, stop bits and data size */ - writel(ucr2 | old_txrxen, sport->port.membase + UCR2); + writel(ucr2 | old_ucr2, sport->port.membase + UCR2); if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) imx_enable_ms(&sport->port); - if (sport->dma_is_inited && !sport->dma_is_enabled) - imx_enable_dma(sport); spin_unlock_irqrestore(&sport->port.lock, flags); } @@ -1498,7 +1502,7 @@ static int imx_poll_init(struct uart_port *port) if (retval) clk_disable_unprepare(sport->clk_ipg); - imx_setup_ufcr(sport, 0); + imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); spin_lock_irqsave(&sport->port.lock, flags); @@ -1768,7 +1772,7 @@ imx_console_setup(struct console *co, char *options) else imx_console_get_options(sport, &baud, &parity, &bits); - imx_setup_ufcr(sport, 0); + imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); retval = uart_set_options(&sport->port, co, baud, parity, bits, flow); @@ -1798,6 +1802,38 @@ static struct console imx_console = { }; #define IMX_CONSOLE &imx_console + +#ifdef CONFIG_OF +static void imx_console_early_putchar(struct uart_port *port, int ch) +{ + while (readl_relaxed(port->membase + IMX21_UTS) & UTS_TXFULL) + cpu_relax(); + + writel_relaxed(ch, port->membase + URTX0); +} + +static void imx_console_early_write(struct console *con, const char *s, + unsigned count) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, count, imx_console_early_putchar); +} + +static int __init +imx_console_early_setup(struct earlycon_device *dev, const char *opt) +{ + if (!dev->port.membase) + return -ENODEV; + + dev->con->write = imx_console_early_write; + + return 0; +} +OF_EARLYCON_DECLARE(ec_imx6q, "fsl,imx6q-uart", imx_console_early_setup); +OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup); +#endif + #else #define IMX_CONSOLE NULL #endif @@ -1812,36 +1848,6 @@ static struct uart_driver imx_reg = { .cons = IMX_CONSOLE, }; -static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) -{ - struct imx_port *sport = platform_get_drvdata(dev); - unsigned int val; - - /* enable wakeup from i.MX UART */ - val = readl(sport->port.membase + UCR3); - val |= UCR3_AWAKEN; - writel(val, sport->port.membase + UCR3); - - uart_suspend_port(&imx_reg, &sport->port); - - return 0; -} - -static int serial_imx_resume(struct platform_device *dev) -{ - struct imx_port *sport = platform_get_drvdata(dev); - unsigned int val; - - /* disable wakeup from i.MX UART */ - val = readl(sport->port.membase + UCR3); - val &= ~UCR3_AWAKEN; - writel(val, sport->port.membase + UCR3); - - uart_resume_port(&imx_reg, &sport->port); - - return 0; -} - #ifdef CONFIG_OF /* * This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it @@ -1903,7 +1909,7 @@ static int serial_imx_probe(struct platform_device *pdev) { struct imx_port *sport; void __iomem *base; - int ret = 0; + int ret = 0, reg; struct resource *res; int txirq, rxirq, rtsirq; @@ -1958,6 +1964,19 @@ static int serial_imx_probe(struct platform_device *pdev) sport->port.uartclk = clk_get_rate(sport->clk_per); + /* For register access, we only need to enable the ipg clock. */ + ret = clk_prepare_enable(sport->clk_ipg); + if (ret) + return ret; + + /* Disable interrupts before requesting them */ + reg = readl_relaxed(sport->port.membase + UCR1); + reg &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | + UCR1_TXMPTYEN | UCR1_RTSDEN); + writel_relaxed(reg, sport->port.membase + UCR1); + + clk_disable_unprepare(sport->clk_ipg); + /* * Allocate the IRQ(s) i.MX1 has three interrupts whereas later * chips only have one interrupt. @@ -1993,16 +2012,135 @@ static int serial_imx_remove(struct platform_device *pdev) return uart_remove_one_port(&imx_reg, &sport->port); } +static void serial_imx_restore_context(struct imx_port *sport) +{ + if (!sport->context_saved) + return; + + writel(sport->saved_reg[4], sport->port.membase + UFCR); + writel(sport->saved_reg[5], sport->port.membase + UESC); + writel(sport->saved_reg[6], sport->port.membase + UTIM); + writel(sport->saved_reg[7], sport->port.membase + UBIR); + writel(sport->saved_reg[8], sport->port.membase + UBMR); + writel(sport->saved_reg[9], sport->port.membase + IMX21_UTS); + writel(sport->saved_reg[0], sport->port.membase + UCR1); + writel(sport->saved_reg[1] | UCR2_SRST, sport->port.membase + UCR2); + writel(sport->saved_reg[2], sport->port.membase + UCR3); + writel(sport->saved_reg[3], sport->port.membase + UCR4); + sport->context_saved = false; +} + +static void serial_imx_save_context(struct imx_port *sport) +{ + /* Save necessary regs */ + sport->saved_reg[0] = readl(sport->port.membase + UCR1); + sport->saved_reg[1] = readl(sport->port.membase + UCR2); + sport->saved_reg[2] = readl(sport->port.membase + UCR3); + sport->saved_reg[3] = readl(sport->port.membase + UCR4); + sport->saved_reg[4] = readl(sport->port.membase + UFCR); + sport->saved_reg[5] = readl(sport->port.membase + UESC); + sport->saved_reg[6] = readl(sport->port.membase + UTIM); + sport->saved_reg[7] = readl(sport->port.membase + UBIR); + sport->saved_reg[8] = readl(sport->port.membase + UBMR); + sport->saved_reg[9] = readl(sport->port.membase + IMX21_UTS); + sport->context_saved = true; +} + +static void serial_imx_enable_wakeup(struct imx_port *sport, bool on) +{ + unsigned int val; + + val = readl(sport->port.membase + UCR3); + if (on) + val |= UCR3_AWAKEN; + else + val &= ~UCR3_AWAKEN; + writel(val, sport->port.membase + UCR3); + + val = readl(sport->port.membase + UCR1); + if (on) + val |= UCR1_RTSDEN; + else + val &= ~UCR1_RTSDEN; + writel(val, sport->port.membase + UCR1); +} + +static int imx_serial_port_suspend_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + int ret; + + ret = clk_enable(sport->clk_ipg); + if (ret) + return ret; + + serial_imx_save_context(sport); + + clk_disable(sport->clk_ipg); + + return 0; +} + +static int imx_serial_port_resume_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + int ret; + + ret = clk_enable(sport->clk_ipg); + if (ret) + return ret; + + serial_imx_restore_context(sport); + + clk_disable(sport->clk_ipg); + + return 0; +} + +static int imx_serial_port_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + + /* enable wakeup from i.MX UART */ + serial_imx_enable_wakeup(sport, true); + + uart_suspend_port(&imx_reg, &sport->port); + + return 0; +} + +static int imx_serial_port_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + + /* disable wakeup from i.MX UART */ + serial_imx_enable_wakeup(sport, false); + + uart_resume_port(&imx_reg, &sport->port); + + return 0; +} + +static const struct dev_pm_ops imx_serial_port_pm_ops = { + .suspend_noirq = imx_serial_port_suspend_noirq, + .resume_noirq = imx_serial_port_resume_noirq, + .suspend = imx_serial_port_suspend, + .resume = imx_serial_port_resume, +}; + static struct platform_driver serial_imx_driver = { .probe = serial_imx_probe, .remove = serial_imx_remove, - .suspend = serial_imx_suspend, - .resume = serial_imx_resume, .id_table = imx_uart_devtype, .driver = { .name = "imx-uart", .of_match_table = imx_uart_dt_ids, + .pm = &imx_serial_port_pm_ops, }, }; diff --git a/kernel/drivers/tty/serial/ioc3_serial.c b/kernel/drivers/tty/serial/ioc3_serial.c index abd7ea26e..27b5fefac 100644 --- a/kernel/drivers/tty/serial/ioc3_serial.c +++ b/kernel/drivers/tty/serial/ioc3_serial.c @@ -2137,7 +2137,8 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) /* register port with the serial core */ - if ((ret = ioc3_serial_core_attach(is, idd))) + ret = ioc3_serial_core_attach(is, idd); + if (ret) goto out4; Num_of_ioc3_cards++; diff --git a/kernel/drivers/tty/serial/ioc4_serial.c b/kernel/drivers/tty/serial/ioc4_serial.c index aa28209f4..e5c42fef6 100644 --- a/kernel/drivers/tty/serial/ioc4_serial.c +++ b/kernel/drivers/tty/serial/ioc4_serial.c @@ -1011,7 +1011,8 @@ static irqreturn_t ioc4_intr(int irq, void *arg) */ for (xx = 0; xx < num_intrs; xx++) { intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx]; - if ((this_mir = this_ir & intr_info->sd_bits)) { + this_mir = this_ir & intr_info->sd_bits; + if (this_mir) { /* Disable owned interrupts, call handler */ handled++; write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC, @@ -2865,10 +2866,12 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) /* register port with the serial core - 1 rs232, 1 rs422 */ - if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232))) + ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232); + if (ret) goto out4; - if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422))) + ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422); + if (ret) goto out5; Num_of_ioc4_cards++; diff --git a/kernel/drivers/tty/serial/kgdb_nmi.c b/kernel/drivers/tty/serial/kgdb_nmi.c index 129dc5be6..117df1516 100644 --- a/kernel/drivers/tty/serial/kgdb_nmi.c +++ b/kernel/drivers/tty/serial/kgdb_nmi.c @@ -173,18 +173,18 @@ static int kgdb_nmi_poll_one_knock(void) bool kgdb_nmi_poll_knock(void) { if (kgdb_nmi_knock < 0) - return 1; + return true; while (1) { int ret; ret = kgdb_nmi_poll_one_knock(); if (ret == NO_POLL_CHAR) - return 0; + return false; else if (ret == 1) break; } - return 1; + return true; } /* diff --git a/kernel/drivers/tty/serial/lantiq.c b/kernel/drivers/tty/serial/lantiq.c index 4ccc03976..b88832e8e 100644 --- a/kernel/drivers/tty/serial/lantiq.c +++ b/kernel/drivers/tty/serial/lantiq.c @@ -21,7 +21,6 @@ */ #include <linux/slab.h> -#include <linux/module.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/console.h> @@ -740,7 +739,6 @@ static const struct of_device_id ltq_asc_match[] = { { .compatible = DRVNAME }, {}, }; -MODULE_DEVICE_TABLE(of, ltq_asc_match); static struct platform_driver lqasc_driver = { .driver = { @@ -764,8 +762,4 @@ init_lqasc(void) return ret; } - -module_init(init_lqasc); - -MODULE_DESCRIPTION("Lantiq serial port driver"); -MODULE_LICENSE("GPL"); +device_initcall(init_lqasc); diff --git a/kernel/drivers/tty/serial/lpc32xx_hs.c b/kernel/drivers/tty/serial/lpc32xx_hs.c index e92d7ebe9..7eb04ae71 100644 --- a/kernel/drivers/tty/serial/lpc32xx_hs.c +++ b/kernel/drivers/tty/serial/lpc32xx_hs.c @@ -691,12 +691,13 @@ static int serial_hs_lpc32xx_probe(struct platform_device *pdev) p->port.mapbase = res->start; p->port.membase = NULL; - p->port.irq = platform_get_irq(pdev, 0); - if (p->port.irq < 0) { + ret = platform_get_irq(pdev, 0); + if (ret < 0) { dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n", uarts_registered); - return p->port.irq; + return ret; } + p->port.irq = ret; p->port.iotype = UPIO_MEM32; p->port.uartclk = LPC32XX_MAIN_OSC_FREQ; diff --git a/kernel/drivers/tty/serial/max3100.c b/kernel/drivers/tty/serial/max3100.c index 077377259..5c4c280b3 100644 --- a/kernel/drivers/tty/serial/max3100.c +++ b/kernel/drivers/tty/serial/max3100.c @@ -904,7 +904,6 @@ static SIMPLE_DEV_PM_OPS(max3100_pm_ops, max3100_suspend, max3100_resume); static struct spi_driver max3100_driver = { .driver = { .name = "max3100", - .owner = THIS_MODULE, .pm = MAX3100_PM_OPS, }, .probe = max3100_probe, diff --git a/kernel/drivers/tty/serial/max310x.c b/kernel/drivers/tty/serial/max310x.c index 182549f55..d45133056 100644 --- a/kernel/drivers/tty/serial/max310x.c +++ b/kernel/drivers/tty/serial/max310x.c @@ -1338,7 +1338,6 @@ MODULE_DEVICE_TABLE(spi, max310x_id_table); static struct spi_driver max310x_uart_driver = { .driver = { .name = MAX310X_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(max310x_dt_ids), .pm = &max310x_pm_ops, }, diff --git a/kernel/drivers/tty/serial/mcf.c b/kernel/drivers/tty/serial/mcf.c index a9b0ab38a..02eb32217 100644 --- a/kernel/drivers/tty/serial/mcf.c +++ b/kernel/drivers/tty/serial/mcf.c @@ -597,7 +597,7 @@ console_initcall(mcf_console_init); #define MCF_CONSOLE NULL /****************************************************************************/ -#endif /* CONFIG_MCF_CONSOLE */ +#endif /* CONFIG_SERIAL_MCF_CONSOLE */ /****************************************************************************/ /* diff --git a/kernel/drivers/tty/serial/men_z135_uart.c b/kernel/drivers/tty/serial/men_z135_uart.c index 5a41b8fbb..3141aa208 100644 --- a/kernel/drivers/tty/serial/men_z135_uart.c +++ b/kernel/drivers/tty/serial/men_z135_uart.c @@ -35,8 +35,6 @@ #define MEN_Z135_BAUD_REG 0x810 #define MEN_Z135_TIMEOUT 0x814 -#define MEN_Z135_MEM_SIZE 0x818 - #define IRQ_ID(x) ((x) & 0x1f) #define MEN_Z135_IER_RXCIEN BIT(0) /* RX Space IRQ */ @@ -124,6 +122,7 @@ MODULE_PARM_DESC(rx_timeout, "RX timeout. " struct men_z135_port { struct uart_port port; struct mcb_device *mdev; + struct resource *mem; unsigned char *rxbuf; u32 stat_reg; spinlock_t lock; @@ -734,22 +733,30 @@ static const char *men_z135_type(struct uart_port *port) static void men_z135_release_port(struct uart_port *port) { + struct men_z135_port *uart = to_men_z135(port); + iounmap(port->membase); port->membase = NULL; - release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE); + mcb_release_mem(uart->mem); } static int men_z135_request_port(struct uart_port *port) { - int size = MEN_Z135_MEM_SIZE; + struct men_z135_port *uart = to_men_z135(port); + struct mcb_device *mdev = uart->mdev; + struct resource *mem; + + mem = mcb_request_mem(uart->mdev, dev_name(&mdev->dev)); + if (IS_ERR(mem)) + return PTR_ERR(mem); - if (!request_mem_region(port->mapbase, size, "men_z135_port")) - return -EBUSY; + port->mapbase = mem->start; + uart->mem = mem; - port->membase = ioremap(port->mapbase, MEN_Z135_MEM_SIZE); + port->membase = ioremap(mem->start, resource_size(mem)); if (port->membase == NULL) { - release_mem_region(port->mapbase, MEN_Z135_MEM_SIZE); + mcb_release_mem(mem); return -ENOMEM; } @@ -839,7 +846,6 @@ static int men_z135_probe(struct mcb_device *mdev, uart->port.membase = NULL; uart->mdev = mdev; - spin_lock_init(&uart->port.lock); spin_lock_init(&uart->lock); err = uart_add_one_port(&men_z135_driver, &uart->port); diff --git a/kernel/drivers/tty/serial/meson_uart.c b/kernel/drivers/tty/serial/meson_uart.c index 67c036702..0fc83c962 100644 --- a/kernel/drivers/tty/serial/meson_uart.c +++ b/kernel/drivers/tty/serial/meson_uart.c @@ -370,7 +370,7 @@ static int meson_uart_verify_port(struct uart_port *port, static void meson_uart_release_port(struct uart_port *port) { if (port->flags & UPF_IOREMAP) { - iounmap(port->membase); + devm_iounmap(port->dev, port->membase); port->membase = NULL; } } diff --git a/kernel/drivers/tty/serial/mpc52xx_uart.c b/kernel/drivers/tty/serial/mpc52xx_uart.c index 1589f17c1..8c3e51314 100644 --- a/kernel/drivers/tty/serial/mpc52xx_uart.c +++ b/kernel/drivers/tty/serial/mpc52xx_uart.c @@ -239,8 +239,9 @@ static int mpc52xx_psc_tx_rdy(struct uart_port *port) static int mpc52xx_psc_tx_empty(struct uart_port *port) { - return in_be16(&PSC(port)->mpc52xx_psc_status) - & MPC52xx_PSC_SR_TXEMP; + u16 sts = in_be16(&PSC(port)->mpc52xx_psc_status); + + return (sts & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0; } static void mpc52xx_psc_start_tx(struct uart_port *port) @@ -405,7 +406,7 @@ static struct psc_ops mpc5200b_psc_ops = { .get_mr1 = mpc52xx_psc_get_mr1, }; -#endif /* CONFIG_MPC52xx */ +#endif /* CONFIG_PPC_MPC52xx */ #ifdef CONFIG_PPC_MPC512x #define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1)) @@ -1134,6 +1135,13 @@ mpc52xx_uart_startup(struct uart_port *port) psc_ops->command(port, MPC52xx_PSC_RST_RX); psc_ops->command(port, MPC52xx_PSC_RST_TX); + /* + * According to Freescale's support the RST_TX command can produce a + * spike on the TX pin. So they recommend to delay "for one character". + * One millisecond should be enough for everyone. + */ + msleep(1); + psc_ops->set_sicr(port, 0); /* UART mode DCD ignored */ psc_ops->fifo_init(port); diff --git a/kernel/drivers/tty/serial/mpsc.c b/kernel/drivers/tty/serial/mpsc.c index 856fd5a5f..cadfd1cfa 100644 --- a/kernel/drivers/tty/serial/mpsc.c +++ b/kernel/drivers/tty/serial/mpsc.c @@ -55,8 +55,6 @@ #define SUPPORT_SYSRQ #endif -#include <linux/module.h> -#include <linux/moduleparam.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/ioport.h> @@ -755,7 +753,7 @@ static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi) pi->port.line); if (!pi->dma_region) { - if (!dma_supported(pi->port.dev, 0xffffffff)) { + if (!dma_set_mask(pi->port.dev, 0xffffffff)) { printk(KERN_ERR "MPSC: Inadequate DMA support\n"); rc = -ENXIO; } else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev, @@ -913,7 +911,8 @@ static int mpsc_make_ready(struct mpsc_port_info *pi) if (!pi->ready) { mpsc_init_hw(pi); - if ((rc = mpsc_alloc_ring_mem(pi))) + rc = mpsc_alloc_ring_mem(pi); + if (rc) return rc; mpsc_init_rings(pi); pi->ready = 1; @@ -1895,7 +1894,8 @@ static int mpsc_shared_drv_probe(struct platform_device *dev) int rc = -ENODEV; if (dev->id == 0) { - if (!(rc = mpsc_shared_map_regs(dev))) { + rc = mpsc_shared_map_regs(dev); + if (!rc) { pdata = (struct mpsc_shared_pdata *) dev_get_platdata(&dev->dev); @@ -2081,14 +2081,16 @@ static int mpsc_drv_probe(struct platform_device *dev) if (dev->id < MPSC_NUM_CTLRS) { pi = &mpsc_ports[dev->id]; - if (!(rc = mpsc_drv_map_regs(pi, dev))) { + rc = mpsc_drv_map_regs(pi, dev); + if (!rc) { mpsc_drv_get_platform_data(pi, dev, dev->id); pi->port.dev = &dev->dev; - if (!(rc = mpsc_make_ready(pi))) { + rc = mpsc_make_ready(pi); + if (!rc) { spin_lock_init(&pi->tx_lock); - if (!(rc = uart_add_one_port(&mpsc_reg, - &pi->port))) { + rc = uart_add_one_port(&mpsc_reg, &pi->port); + if (!rc) { rc = 0; } else { mpsc_release_port((struct uart_port *) @@ -2104,26 +2106,11 @@ static int mpsc_drv_probe(struct platform_device *dev) return rc; } -static int mpsc_drv_remove(struct platform_device *dev) -{ - pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id); - - if (dev->id < MPSC_NUM_CTLRS) { - uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port); - mpsc_release_port((struct uart_port *) - &mpsc_ports[dev->id].port); - mpsc_drv_unmap_regs(&mpsc_ports[dev->id]); - return 0; - } else { - return -ENODEV; - } -} - static struct platform_driver mpsc_driver = { .probe = mpsc_drv_probe, - .remove = mpsc_drv_remove, .driver = { - .name = MPSC_CTLR_NAME, + .name = MPSC_CTLR_NAME, + .suppress_bind_attrs = true, }, }; @@ -2136,9 +2123,12 @@ static int __init mpsc_drv_init(void) memset(mpsc_ports, 0, sizeof(mpsc_ports)); memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs)); - if (!(rc = uart_register_driver(&mpsc_reg))) { - if (!(rc = platform_driver_register(&mpsc_shared_driver))) { - if ((rc = platform_driver_register(&mpsc_driver))) { + rc = uart_register_driver(&mpsc_reg); + if (!rc) { + rc = platform_driver_register(&mpsc_shared_driver); + if (!rc) { + rc = platform_driver_register(&mpsc_driver); + if (rc) { platform_driver_unregister(&mpsc_shared_driver); uart_unregister_driver(&mpsc_reg); } @@ -2149,22 +2139,10 @@ static int __init mpsc_drv_init(void) return rc; } +device_initcall(mpsc_drv_init); -static void __exit mpsc_drv_exit(void) -{ - platform_driver_unregister(&mpsc_driver); - platform_driver_unregister(&mpsc_shared_driver); - uart_unregister_driver(&mpsc_reg); - memset(mpsc_ports, 0, sizeof(mpsc_ports)); - memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs)); -} - -module_init(mpsc_drv_init); -module_exit(mpsc_drv_exit); - +/* MODULE_AUTHOR("Mark A. Greer <mgreer@mvista.com>"); MODULE_DESCRIPTION("Generic Marvell MPSC serial/UART driver"); -MODULE_VERSION(MPSC_VERSION); MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(MPSC_MAJOR); -MODULE_ALIAS("platform:" MPSC_CTLR_NAME); +*/ diff --git a/kernel/drivers/tty/serial/msm_serial.c b/kernel/drivers/tty/serial/msm_serial.c index b73889c8e..dcde95547 100644 --- a/kernel/drivers/tty/serial/msm_serial.c +++ b/kernel/drivers/tty/serial/msm_serial.c @@ -20,6 +20,8 @@ #endif #include <linux/atomic.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> #include <linux/hrtimer.h> #include <linux/module.h> #include <linux/io.h> @@ -31,6 +33,7 @@ #include <linux/tty_flip.h> #include <linux/serial_core.h> #include <linux/serial.h> +#include <linux/slab.h> #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/delay.h> @@ -39,6 +42,11 @@ #include "msm_serial.h" +#define UARTDM_BURST_SIZE 16 /* in bytes */ +#define UARTDM_TX_AIGN(x) ((x) & ~0x3) /* valid for > 1p3 */ +#define UARTDM_TX_MAX 256 /* in bytes, valid for <= 1p3 */ +#define UARTDM_RX_SIZE (UART_XMIT_SIZE / 4) + enum { UARTDM_1P1 = 1, UARTDM_1P2, @@ -46,6 +54,17 @@ enum { UARTDM_1P4, }; +struct msm_dma { + struct dma_chan *chan; + enum dma_data_direction dir; + dma_addr_t phys; + unsigned char *virt; + dma_cookie_t cookie; + u32 enable_bit; + unsigned int count; + struct dma_async_tx_descriptor *desc; +}; + struct msm_port { struct uart_port uart; char name[16]; @@ -55,9 +74,153 @@ struct msm_port { int is_uartdm; unsigned int old_snap_state; bool break_detected; + struct msm_dma tx_dma; + struct msm_dma rx_dma; }; -static inline void wait_for_xmitr(struct uart_port *port) +static void msm_handle_tx(struct uart_port *port); +static void msm_start_rx_dma(struct msm_port *msm_port); + +void msm_stop_dma(struct uart_port *port, struct msm_dma *dma) +{ + struct device *dev = port->dev; + unsigned int mapped; + u32 val; + + mapped = dma->count; + dma->count = 0; + + dmaengine_terminate_all(dma->chan); + + /* + * DMA Stall happens if enqueue and flush command happens concurrently. + * For example before changing the baud rate/protocol configuration and + * sending flush command to ADM, disable the channel of UARTDM. + * Note: should not reset the receiver here immediately as it is not + * suggested to do disable/reset or reset/disable at the same time. + */ + val = msm_read(port, UARTDM_DMEN); + val &= ~dma->enable_bit; + msm_write(port, val, UARTDM_DMEN); + + if (mapped) + dma_unmap_single(dev, dma->phys, mapped, dma->dir); +} + +static void msm_release_dma(struct msm_port *msm_port) +{ + struct msm_dma *dma; + + dma = &msm_port->tx_dma; + if (dma->chan) { + msm_stop_dma(&msm_port->uart, dma); + dma_release_channel(dma->chan); + } + + memset(dma, 0, sizeof(*dma)); + + dma = &msm_port->rx_dma; + if (dma->chan) { + msm_stop_dma(&msm_port->uart, dma); + dma_release_channel(dma->chan); + kfree(dma->virt); + } + + memset(dma, 0, sizeof(*dma)); +} + +static void msm_request_tx_dma(struct msm_port *msm_port, resource_size_t base) +{ + struct device *dev = msm_port->uart.dev; + struct dma_slave_config conf; + struct msm_dma *dma; + u32 crci = 0; + int ret; + + dma = &msm_port->tx_dma; + + /* allocate DMA resources, if available */ + dma->chan = dma_request_slave_channel_reason(dev, "tx"); + if (IS_ERR(dma->chan)) + goto no_tx; + + of_property_read_u32(dev->of_node, "qcom,tx-crci", &crci); + + memset(&conf, 0, sizeof(conf)); + conf.direction = DMA_MEM_TO_DEV; + conf.device_fc = true; + conf.dst_addr = base + UARTDM_TF; + conf.dst_maxburst = UARTDM_BURST_SIZE; + conf.slave_id = crci; + + ret = dmaengine_slave_config(dma->chan, &conf); + if (ret) + goto rel_tx; + + dma->dir = DMA_TO_DEVICE; + + if (msm_port->is_uartdm < UARTDM_1P4) + dma->enable_bit = UARTDM_DMEN_TX_DM_ENABLE; + else + dma->enable_bit = UARTDM_DMEN_TX_BAM_ENABLE; + + return; + +rel_tx: + dma_release_channel(dma->chan); +no_tx: + memset(dma, 0, sizeof(*dma)); +} + +static void msm_request_rx_dma(struct msm_port *msm_port, resource_size_t base) +{ + struct device *dev = msm_port->uart.dev; + struct dma_slave_config conf; + struct msm_dma *dma; + u32 crci = 0; + int ret; + + dma = &msm_port->rx_dma; + + /* allocate DMA resources, if available */ + dma->chan = dma_request_slave_channel_reason(dev, "rx"); + if (IS_ERR(dma->chan)) + goto no_rx; + + of_property_read_u32(dev->of_node, "qcom,rx-crci", &crci); + + dma->virt = kzalloc(UARTDM_RX_SIZE, GFP_KERNEL); + if (!dma->virt) + goto rel_rx; + + memset(&conf, 0, sizeof(conf)); + conf.direction = DMA_DEV_TO_MEM; + conf.device_fc = true; + conf.src_addr = base + UARTDM_RF; + conf.src_maxburst = UARTDM_BURST_SIZE; + conf.slave_id = crci; + + ret = dmaengine_slave_config(dma->chan, &conf); + if (ret) + goto err; + + dma->dir = DMA_FROM_DEVICE; + + if (msm_port->is_uartdm < UARTDM_1P4) + dma->enable_bit = UARTDM_DMEN_RX_DM_ENABLE; + else + dma->enable_bit = UARTDM_DMEN_RX_BAM_ENABLE; + + return; +err: + kfree(dma->virt); +rel_rx: + dma_release_channel(dma->chan); +no_rx: + memset(dma, 0, sizeof(*dma)); +} + +static inline void msm_wait_for_xmitr(struct uart_port *port) { while (!(msm_read(port, UART_SR) & UART_SR_TX_EMPTY)) { if (msm_read(port, UART_ISR) & UART_ISR_TX_READY) @@ -78,17 +241,277 @@ static void msm_stop_tx(struct uart_port *port) static void msm_start_tx(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_dma *dma = &msm_port->tx_dma; + + /* Already started in DMA mode */ + if (dma->count) + return; + + msm_port->imr |= UART_IMR_TXLEV; + msm_write(port, msm_port->imr, UART_IMR); +} + +static void msm_reset_dm_count(struct uart_port *port, int count) +{ + msm_wait_for_xmitr(port); + msm_write(port, count, UARTDM_NCF_TX); + msm_read(port, UARTDM_NCF_TX); +} + +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 msm_dma *dma = &msm_port->tx_dma; + struct dma_tx_state state; + enum dma_status status; + unsigned long flags; + unsigned int count; + u32 val; + + spin_lock_irqsave(&port->lock, flags); + + /* Already stopped */ + if (!dma->count) + goto done; + + status = dmaengine_tx_status(dma->chan, dma->cookie, &state); + + dma_unmap_single(port->dev, dma->phys, dma->count, dma->dir); + val = msm_read(port, UARTDM_DMEN); + val &= ~dma->enable_bit; + msm_write(port, val, UARTDM_DMEN); + + if (msm_port->is_uartdm > UARTDM_1P3) { + msm_write(port, UART_CR_CMD_RESET_TX, UART_CR); + msm_write(port, UART_CR_TX_ENABLE, UART_CR); + } + + count = dma->count - state.residue; + port->icount.tx += count; + dma->count = 0; + + xmit->tail += count; + xmit->tail &= UART_XMIT_SIZE - 1; + + /* Restore "Tx FIFO below watermark" interrupt */ msm_port->imr |= UART_IMR_TXLEV; msm_write(port, msm_port->imr, UART_IMR); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + msm_handle_tx(port); +done: + spin_unlock_irqrestore(&port->lock, flags); +} + +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 msm_dma *dma = &msm_port->tx_dma; + void *cpu_addr; + int ret; + u32 val; + + cpu_addr = &xmit->buf[xmit->tail]; + + dma->phys = dma_map_single(port->dev, cpu_addr, count, dma->dir); + ret = dma_mapping_error(port->dev, dma->phys); + if (ret) + return ret; + + dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys, + count, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | + DMA_PREP_FENCE); + if (!dma->desc) { + ret = -EIO; + goto unmap; + } + + dma->desc->callback = msm_complete_tx_dma; + dma->desc->callback_param = msm_port; + + dma->cookie = dmaengine_submit(dma->desc); + ret = dma_submit_error(dma->cookie); + if (ret) + goto unmap; + + /* + * Using DMA complete for Tx FIFO reload, no need for + * "Tx FIFO below watermark" one, disable it + */ + msm_port->imr &= ~UART_IMR_TXLEV; + msm_write(port, msm_port->imr, UART_IMR); + + dma->count = count; + + val = msm_read(port, UARTDM_DMEN); + val |= dma->enable_bit; + + if (msm_port->is_uartdm < UARTDM_1P4) + msm_write(port, val, UARTDM_DMEN); + + msm_reset_dm_count(port, count); + + if (msm_port->is_uartdm > UARTDM_1P3) + msm_write(port, val, UARTDM_DMEN); + + dma_async_issue_pending(dma->chan); + return 0; +unmap: + dma_unmap_single(port->dev, dma->phys, count, dma->dir); + return ret; +} + +static void msm_complete_rx_dma(void *args) +{ + struct msm_port *msm_port = args; + struct uart_port *port = &msm_port->uart; + struct tty_port *tport = &port->state->port; + struct msm_dma *dma = &msm_port->rx_dma; + int count = 0, i, sysrq; + unsigned long flags; + u32 val; + + spin_lock_irqsave(&port->lock, flags); + + /* Already stopped */ + if (!dma->count) + goto done; + + val = msm_read(port, UARTDM_DMEN); + val &= ~dma->enable_bit; + msm_write(port, val, UARTDM_DMEN); + + /* Restore interrupts */ + msm_port->imr |= UART_IMR_RXLEV | UART_IMR_RXSTALE; + msm_write(port, msm_port->imr, UART_IMR); + + if (msm_read(port, UART_SR) & UART_SR_OVERRUN) { + port->icount.overrun++; + tty_insert_flip_char(tport, 0, TTY_OVERRUN); + msm_write(port, UART_CR_CMD_RESET_ERR, UART_CR); + } + + count = msm_read(port, UARTDM_RX_TOTAL_SNAP); + + port->icount.rx += count; + + dma->count = 0; + + dma_unmap_single(port->dev, dma->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) { + port->icount.brk++; + flag = TTY_BREAK; + msm_port->break_detected = false; + if (uart_handle_break(port)) + continue; + } + + if (!(port->read_status_mask & UART_SR_RX_BREAK)) + flag = TTY_NORMAL; + + spin_unlock_irqrestore(&port->lock, flags); + sysrq = uart_handle_sysrq_char(port, dma->virt[i]); + spin_lock_irqsave(&port->lock, flags); + if (!sysrq) + tty_insert_flip_char(tport, dma->virt[i], flag); + } + + msm_start_rx_dma(msm_port); +done: + spin_unlock_irqrestore(&port->lock, flags); + + if (count) + tty_flip_buffer_push(tport); +} + +static void msm_start_rx_dma(struct msm_port *msm_port) +{ + struct msm_dma *dma = &msm_port->rx_dma; + struct uart_port *uart = &msm_port->uart; + u32 val; + int ret; + + if (!dma->chan) + return; + + dma->phys = dma_map_single(uart->dev, dma->virt, + UARTDM_RX_SIZE, dma->dir); + ret = dma_mapping_error(uart->dev, dma->phys); + if (ret) + return; + + dma->desc = dmaengine_prep_slave_single(dma->chan, dma->phys, + UARTDM_RX_SIZE, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!dma->desc) + goto unmap; + + dma->desc->callback = msm_complete_rx_dma; + dma->desc->callback_param = msm_port; + + dma->cookie = dmaengine_submit(dma->desc); + ret = dma_submit_error(dma->cookie); + if (ret) + goto unmap; + /* + * Using DMA for FIFO off-load, no need for "Rx FIFO over + * watermark" or "stale" interrupts, disable them + */ + msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); + + /* + * Well, when DMA is ADM3 engine(implied by <= UARTDM v1.3), + * we need RXSTALE to flush input DMA fifo to memory + */ + if (msm_port->is_uartdm < UARTDM_1P4) + msm_port->imr |= UART_IMR_RXSTALE; + + msm_write(uart, msm_port->imr, UART_IMR); + + dma->count = UARTDM_RX_SIZE; + + dma_async_issue_pending(dma->chan); + + msm_write(uart, UART_CR_CMD_RESET_STALE_INT, UART_CR); + msm_write(uart, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + + val = msm_read(uart, UARTDM_DMEN); + val |= dma->enable_bit; + + if (msm_port->is_uartdm < UARTDM_1P4) + msm_write(uart, val, UARTDM_DMEN); + + msm_write(uart, UARTDM_RX_SIZE, UARTDM_DMRX); + + if (msm_port->is_uartdm > UARTDM_1P3) + msm_write(uart, val, UARTDM_DMEN); + + return; +unmap: + dma_unmap_single(uart->dev, dma->phys, UARTDM_RX_SIZE, dma->dir); } static void msm_stop_rx(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_dma *dma = &msm_port->rx_dma; msm_port->imr &= ~(UART_IMR_RXLEV | UART_IMR_RXSTALE); msm_write(port, msm_port->imr, UART_IMR); + + if (dma->chan) + msm_stop_dma(port, dma); } static void msm_enable_ms(struct uart_port *port) @@ -99,7 +522,7 @@ static void msm_enable_ms(struct uart_port *port) msm_write(port, msm_port->imr, UART_IMR); } -static void handle_rx_dm(struct uart_port *port, unsigned int misr) +static void msm_handle_rx_dm(struct uart_port *port, unsigned int misr) { struct tty_port *tport = &port->state->port; unsigned int sr; @@ -169,9 +592,12 @@ static void handle_rx_dm(struct uart_port *port, unsigned int misr) msm_write(port, UART_CR_CMD_RESET_STALE_INT, UART_CR); msm_write(port, 0xFFFFFF, UARTDM_DMRX); msm_write(port, UART_CR_CMD_STALE_EVENT_ENABLE, UART_CR); + + /* Try to use DMA */ + msm_start_rx_dma(msm_port); } -static void handle_rx(struct uart_port *port) +static void msm_handle_rx(struct uart_port *port) { struct tty_port *tport = &port->state->port; unsigned int sr; @@ -224,18 +650,11 @@ static void handle_rx(struct uart_port *port) spin_lock(&port->lock); } -static void reset_dm_count(struct uart_port *port, int count) -{ - wait_for_xmitr(port); - msm_write(port, count, UARTDM_NCF_TX); - msm_read(port, UARTDM_NCF_TX); -} - -static void handle_tx(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 = UART_TO_MSM(port); - unsigned int tx_count, num_chars; + unsigned int num_chars; unsigned int tf_pointer = 0; void __iomem *tf; @@ -244,20 +663,8 @@ static void handle_tx(struct uart_port *port) else tf = port->membase + UART_TF; - tx_count = uart_circ_chars_pending(xmit); - tx_count = min3(tx_count, (unsigned int)UART_XMIT_SIZE - xmit->tail, - port->fifosize); - - if (port->x_char) { - if (msm_port->is_uartdm) - reset_dm_count(port, tx_count + 1); - - iowrite8_rep(tf, &port->x_char, 1); - port->icount.tx++; - port->x_char = 0; - } else if (tx_count && msm_port->is_uartdm) { - reset_dm_count(port, tx_count); - } + if (tx_count && msm_port->is_uartdm) + msm_reset_dm_count(port, tx_count); while (tf_pointer < tx_count) { int i; @@ -290,20 +697,76 @@ static void handle_tx(struct uart_port *port) uart_write_wakeup(port); } -static void handle_delta_cts(struct uart_port *port) +static void msm_handle_tx(struct uart_port *port) +{ + struct msm_port *msm_port = UART_TO_MSM(port); + struct circ_buf *xmit = &msm_port->uart.state->xmit; + struct msm_dma *dma = &msm_port->tx_dma; + unsigned int pio_count, dma_count, dma_min; + void __iomem *tf; + int err = 0; + + if (port->x_char) { + if (msm_port->is_uartdm) + tf = port->membase + UARTDM_TF; + else + tf = port->membase + UART_TF; + + if (msm_port->is_uartdm) + msm_reset_dm_count(port, 1); + + iowrite8_rep(tf, &port->x_char, 1); + port->icount.tx++; + port->x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + msm_stop_tx(port); + return; + } + + pio_count = CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE); + dma_count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + + dma_min = 1; /* Always DMA */ + if (msm_port->is_uartdm > UARTDM_1P3) { + dma_count = UARTDM_TX_AIGN(dma_count); + dma_min = UARTDM_BURST_SIZE; + } else { + if (dma_count > UARTDM_TX_MAX) + dma_count = UARTDM_TX_MAX; + } + + if (pio_count > port->fifosize) + pio_count = port->fifosize; + + if (!dma->chan || dma_count < dma_min) + msm_handle_tx_pio(port, pio_count); + else + err = msm_handle_tx_dma(msm_port, dma_count); + + if (err) /* fall back to PIO mode */ + msm_handle_tx_pio(port, pio_count); +} + +static void msm_handle_delta_cts(struct uart_port *port) { msm_write(port, UART_CR_CMD_RESET_CTS, UART_CR); port->icount.cts++; wake_up_interruptible(&port->state->port.delta_msr_wait); } -static irqreturn_t msm_irq(int irq, void *dev_id) +static irqreturn_t msm_uart_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_dma *dma = &msm_port->rx_dma; + unsigned long flags; unsigned int misr; + u32 val; - spin_lock(&port->lock); + spin_lock_irqsave(&port->lock, flags); misr = msm_read(port, UART_MISR); msm_write(port, 0, UART_IMR); /* disable interrupt */ @@ -313,18 +776,29 @@ static irqreturn_t msm_irq(int irq, void *dev_id) } if (misr & (UART_IMR_RXLEV | UART_IMR_RXSTALE)) { - if (msm_port->is_uartdm) - handle_rx_dm(port, misr); - else - handle_rx(port); + if (dma->count) { + val = UART_CR_CMD_STALE_EVENT_DISABLE; + msm_write(port, val, UART_CR); + val = UART_CR_CMD_RESET_STALE_INT; + msm_write(port, val, UART_CR); + /* + * Flush DMA input fifo to memory, this will also + * trigger DMA RX completion + */ + dmaengine_terminate_all(dma->chan); + } else if (msm_port->is_uartdm) { + msm_handle_rx_dm(port, misr); + } else { + msm_handle_rx(port); + } } if (misr & UART_IMR_TXLEV) - handle_tx(port); + msm_handle_tx(port); if (misr & UART_IMR_DELTA_CTS) - handle_delta_cts(port); + msm_handle_delta_cts(port); msm_write(port, msm_port->imr, UART_IMR); /* restore interrupt */ - spin_unlock(&port->lock); + spin_unlock_irqrestore(&port->lock, flags); return IRQ_HANDLED; } @@ -408,6 +882,7 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud) { 3, 0xdd, 8 }, { 2, 0xee, 16 }, { 1, 0xff, 31 }, + { 0, 0xff, 31 }, }; divisor = uart_get_divisor(port, baud); @@ -419,21 +894,41 @@ msm_find_best_baud(struct uart_port *port, unsigned int baud) return entry; /* Default to smallest divider */ } -static int msm_set_baud_rate(struct uart_port *port, unsigned int baud) +static int msm_set_baud_rate(struct uart_port *port, unsigned int baud, + unsigned long *saved_flags) { - unsigned int rxstale, watermark; + unsigned int rxstale, watermark, mask; struct msm_port *msm_port = UART_TO_MSM(port); const struct msm_baud_map *entry; + unsigned long flags; entry = msm_find_best_baud(port, baud); msm_write(port, entry->code, UART_CSR); + if (baud > 460800) + port->uartclk = baud * 16; + + flags = *saved_flags; + spin_unlock_irqrestore(&port->lock, flags); + + clk_set_rate(msm_port->clk, port->uartclk); + + spin_lock_irqsave(&port->lock, flags); + *saved_flags = flags; + /* RX stale watermark */ rxstale = entry->rxstale; watermark = UART_IPR_STALE_LSB & rxstale; - watermark |= UART_IPR_RXSTALE_LAST; - watermark |= UART_IPR_STALE_TIMEOUT_MSB & (rxstale << 2); + if (msm_port->is_uartdm) { + mask = UART_DM_IPR_STALE_TIMEOUT_MSB; + } else { + watermark |= UART_IPR_RXSTALE_LAST; + mask = UART_IPR_STALE_TIMEOUT_MSB; + } + + watermark |= mask & (rxstale << 2); + msm_write(port, watermark, UART_IPR); /* set RX watermark */ @@ -476,13 +971,13 @@ static void msm_init_clock(struct uart_port *port) static int msm_startup(struct uart_port *port) { struct msm_port *msm_port = UART_TO_MSM(port); - unsigned int data, rfr_level; + unsigned int data, rfr_level, mask; int ret; snprintf(msm_port->name, sizeof(msm_port->name), "msm_serial%d", port->line); - ret = request_irq(port->irq, msm_irq, IRQF_TRIGGER_HIGH, + ret = request_irq(port->irq, msm_uart_irq, IRQF_TRIGGER_HIGH, msm_port->name, port); if (unlikely(ret)) return ret; @@ -496,11 +991,23 @@ static int msm_startup(struct uart_port *port) /* set automatic RFR level */ data = msm_read(port, UART_MR1); - data &= ~UART_MR1_AUTO_RFR_LEVEL1; + + if (msm_port->is_uartdm) + mask = UART_DM_MR1_AUTO_RFR_LEVEL1; + else + mask = UART_MR1_AUTO_RFR_LEVEL1; + + data &= ~mask; data &= ~UART_MR1_AUTO_RFR_LEVEL0; - data |= UART_MR1_AUTO_RFR_LEVEL1 & (rfr_level << 2); + data |= mask & (rfr_level << 2); data |= UART_MR1_AUTO_RFR_LEVEL0 & rfr_level; msm_write(port, data, UART_MR1); + + if (msm_port->is_uartdm) { + msm_request_tx_dma(msm_port, msm_port->uart.mapbase); + msm_request_rx_dma(msm_port, msm_port->uart.mapbase); + } + return 0; } @@ -511,6 +1018,9 @@ static void msm_shutdown(struct uart_port *port) msm_port->imr = 0; msm_write(port, 0, UART_IMR); /* disable interrupts */ + if (msm_port->is_uartdm) + msm_release_dma(msm_port); + clk_disable_unprepare(msm_port->clk); free_irq(port->irq, port); @@ -519,14 +1029,19 @@ static void msm_shutdown(struct uart_port *port) static void msm_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { + struct msm_port *msm_port = UART_TO_MSM(port); + struct msm_dma *dma = &msm_port->rx_dma; unsigned long flags; unsigned int baud, mr; spin_lock_irqsave(&port->lock, flags); + if (dma->chan) /* Terminate if any */ + msm_stop_dma(port, dma); + /* calculate and set baud rate */ - baud = uart_get_baud_rate(port, termios, old, 300, 115200); - baud = msm_set_baud_rate(port, baud); + baud = uart_get_baud_rate(port, termios, old, 300, 4000000); + baud = msm_set_baud_rate(port, baud, &flags); if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); @@ -588,6 +1103,9 @@ static void msm_set_termios(struct uart_port *port, struct ktermios *termios, uart_update_timeout(port, termios->c_cflag, baud); + /* Try to use DMA */ + msm_start_rx_dma(msm_port); + spin_unlock_irqrestore(&port->lock, flags); } @@ -765,7 +1283,7 @@ static void msm_poll_put_char(struct uart_port *port, unsigned char c) msm_write(port, 0, UART_IMR); if (msm_port->is_uartdm) - reset_dm_count(port, 1); + msm_reset_dm_count(port, 1); /* Wait until FIFO is empty */ while (!(msm_read(port, UART_SR) & UART_SR_TX_READY)) @@ -839,7 +1357,7 @@ static struct msm_port msm_uart_ports[] = { #define UART_NR ARRAY_SIZE(msm_uart_ports) -static inline struct uart_port *get_port_from_line(unsigned int line) +static inline struct uart_port *msm_get_port_from_line(unsigned int line) { return &msm_uart_ports[line].uart; } @@ -866,7 +1384,7 @@ static void __msm_console_write(struct uart_port *port, const char *s, spin_lock(&port->lock); if (is_uartdm) - reset_dm_count(port, count); + msm_reset_dm_count(port, count); i = 0; while (i < count) { @@ -911,7 +1429,7 @@ static void msm_console_write(struct console *co, const char *s, BUG_ON(co->index < 0 || co->index >= UART_NR); - port = get_port_from_line(co->index); + port = msm_get_port_from_line(co->index); msm_port = UART_TO_MSM(port); __msm_console_write(port, s, count, msm_port->is_uartdm); @@ -928,7 +1446,7 @@ static int __init msm_console_setup(struct console *co, char *options) if (unlikely(co->index >= UART_NR || co->index < 0)) return -ENXIO; - port = get_port_from_line(co->index); + port = msm_get_port_from_line(co->index); if (unlikely(!port->membase)) return -ENXIO; @@ -1043,7 +1561,7 @@ static int msm_serial_probe(struct platform_device *pdev) dev_info(&pdev->dev, "msm_serial: detected port #%d\n", line); - port = get_port_from_line(line); + port = msm_get_port_from_line(line); port->dev = &pdev->dev; msm_port = UART_TO_MSM(port); diff --git a/kernel/drivers/tty/serial/msm_serial.h b/kernel/drivers/tty/serial/msm_serial.h index 737f69fe7..178645826 100644 --- a/kernel/drivers/tty/serial/msm_serial.h +++ b/kernel/drivers/tty/serial/msm_serial.h @@ -20,11 +20,12 @@ #define UART_MR1_AUTO_RFR_LEVEL0 0x3F #define UART_MR1_AUTO_RFR_LEVEL1 0x3FF00 -#define UART_MR1_RX_RDY_CTL (1 << 7) -#define UART_MR1_CTS_CTL (1 << 6) +#define UART_DM_MR1_AUTO_RFR_LEVEL1 0xFFFFFF00 +#define UART_MR1_RX_RDY_CTL BIT(7) +#define UART_MR1_CTS_CTL BIT(6) #define UART_MR2 0x0004 -#define UART_MR2_ERROR_MODE (1 << 6) +#define UART_MR2_ERROR_MODE BIT(6) #define UART_MR2_BITS_PER_CHAR 0x30 #define UART_MR2_BITS_PER_CHAR_5 (0x0 << 4) #define UART_MR2_BITS_PER_CHAR_6 (0x1 << 4) @@ -58,26 +59,28 @@ #define UART_CR_CMD_SET_RFR (13 << 4) #define UART_CR_CMD_RESET_RFR (14 << 4) #define UART_CR_CMD_PROTECTION_EN (16 << 4) +#define UART_CR_CMD_STALE_EVENT_DISABLE (6 << 8) #define UART_CR_CMD_STALE_EVENT_ENABLE (80 << 4) #define UART_CR_CMD_FORCE_STALE (4 << 8) #define UART_CR_CMD_RESET_TX_READY (3 << 8) -#define UART_CR_TX_DISABLE (1 << 3) -#define UART_CR_TX_ENABLE (1 << 2) -#define UART_CR_RX_DISABLE (1 << 1) -#define UART_CR_RX_ENABLE (1 << 0) +#define UART_CR_TX_DISABLE BIT(3) +#define UART_CR_TX_ENABLE BIT(2) +#define UART_CR_RX_DISABLE BIT(1) +#define UART_CR_RX_ENABLE BIT(0) #define UART_CR_CMD_RESET_RXBREAK_START ((1 << 11) | (2 << 4)) #define UART_IMR 0x0014 -#define UART_IMR_TXLEV (1 << 0) -#define UART_IMR_RXSTALE (1 << 3) -#define UART_IMR_RXLEV (1 << 4) -#define UART_IMR_DELTA_CTS (1 << 5) -#define UART_IMR_CURRENT_CTS (1 << 6) -#define UART_IMR_RXBREAK_START (1 << 10) +#define UART_IMR_TXLEV BIT(0) +#define UART_IMR_RXSTALE BIT(3) +#define UART_IMR_RXLEV BIT(4) +#define UART_IMR_DELTA_CTS BIT(5) +#define UART_IMR_CURRENT_CTS BIT(6) +#define UART_IMR_RXBREAK_START BIT(10) #define UART_IPR_RXSTALE_LAST 0x20 #define UART_IPR_STALE_LSB 0x1F #define UART_IPR_STALE_TIMEOUT_MSB 0x3FF80 +#define UART_DM_IPR_STALE_TIMEOUT_MSB 0xFFFFFF80 #define UART_IPR 0x0018 #define UART_TFWR 0x001C @@ -96,20 +99,20 @@ #define UART_TEST_CTRL 0x0050 #define UART_SR 0x0008 -#define UART_SR_HUNT_CHAR (1 << 7) -#define UART_SR_RX_BREAK (1 << 6) -#define UART_SR_PAR_FRAME_ERR (1 << 5) -#define UART_SR_OVERRUN (1 << 4) -#define UART_SR_TX_EMPTY (1 << 3) -#define UART_SR_TX_READY (1 << 2) -#define UART_SR_RX_FULL (1 << 1) -#define UART_SR_RX_READY (1 << 0) +#define UART_SR_HUNT_CHAR BIT(7) +#define UART_SR_RX_BREAK BIT(6) +#define UART_SR_PAR_FRAME_ERR BIT(5) +#define UART_SR_OVERRUN BIT(4) +#define UART_SR_TX_EMPTY BIT(3) +#define UART_SR_TX_READY BIT(2) +#define UART_SR_RX_FULL BIT(1) +#define UART_SR_RX_READY BIT(0) #define UART_RF 0x000C #define UARTDM_RF 0x0070 #define UART_MISR 0x0010 #define UART_ISR 0x0014 -#define UART_ISR_TX_READY (1 << 7) +#define UART_ISR_TX_READY BIT(7) #define UARTDM_RXFS 0x50 #define UARTDM_RXFS_BUF_SHIFT 0x7 @@ -119,6 +122,12 @@ #define UARTDM_DMEN_RX_SC_ENABLE BIT(5) #define UARTDM_DMEN_TX_SC_ENABLE BIT(4) +#define UARTDM_DMEN_TX_BAM_ENABLE BIT(2) /* UARTDM_1P4 */ +#define UARTDM_DMEN_TX_DM_ENABLE BIT(0) /* < UARTDM_1P4 */ + +#define UARTDM_DMEN_RX_BAM_ENABLE BIT(3) /* UARTDM_1P4 */ +#define UARTDM_DMEN_RX_DM_ENABLE BIT(1) /* < UARTDM_1P4 */ + #define UARTDM_DMRX 0x34 #define UARTDM_NCF_TX 0x40 #define UARTDM_RX_TOTAL_SNAP 0x38 diff --git a/kernel/drivers/tty/serial/msm_smd_tty.c b/kernel/drivers/tty/serial/msm_smd_tty.c deleted file mode 100644 index 1238ac370..000000000 --- a/kernel/drivers/tty/serial/msm_smd_tty.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2007 Google, Inc. - * Copyright (c) 2011, Code Aurora Forum. All rights reserved. - * Author: Brian Swetland <swetland@google.com> - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/cdev.h> -#include <linux/device.h> -#include <linux/wait.h> - -#include <linux/tty.h> -#include <linux/tty_driver.h> -#include <linux/tty_flip.h> - -#include <mach/msm_smd.h> - -#define MAX_SMD_TTYS 32 - -struct smd_tty_info { - struct tty_port port; - smd_channel_t *ch; -}; - -struct smd_tty_channel_desc { - int id; - const char *name; -}; - -static struct smd_tty_info smd_tty[MAX_SMD_TTYS]; - -static const struct smd_tty_channel_desc smd_default_tty_channels[] = { - { .id = 0, .name = "SMD_DS" }, - { .id = 27, .name = "SMD_GPSNMEA" }, -}; - -static const struct smd_tty_channel_desc *smd_tty_channels = - smd_default_tty_channels; -static int smd_tty_channels_len = ARRAY_SIZE(smd_default_tty_channels); - -static void smd_tty_notify(void *priv, unsigned event) -{ - unsigned char *ptr; - int avail; - struct smd_tty_info *info = priv; - struct tty_struct *tty; - - if (event != SMD_EVENT_DATA) - return; - - tty = tty_port_tty_get(&info->port); - if (!tty) - return; - - for (;;) { - if (test_bit(TTY_THROTTLED, &tty->flags)) - break; - avail = smd_read_avail(info->ch); - if (avail == 0) - break; - - avail = tty_prepare_flip_string(&info->port, &ptr, avail); - - if (smd_read(info->ch, ptr, avail) != avail) { - /* shouldn't be possible since we're in interrupt - ** context here and nobody else could 'steal' our - ** characters. - */ - pr_err("OOPS - smd_tty_buffer mismatch?!"); - } - - tty_flip_buffer_push(&info->port); - } - - /* XXX only when writable and necessary */ - tty_wakeup(tty); - tty_kref_put(tty); -} - -static int smd_tty_port_activate(struct tty_port *tport, struct tty_struct *tty) -{ - struct smd_tty_info *info = container_of(tport, struct smd_tty_info, - port); - int i, res = 0; - const char *name = NULL; - - for (i = 0; i < smd_tty_channels_len; i++) { - if (smd_tty_channels[i].id == tty->index) { - name = smd_tty_channels[i].name; - break; - } - } - if (!name) - return -ENODEV; - - if (info->ch) - smd_kick(info->ch); - else - res = smd_open(name, &info->ch, info, smd_tty_notify); - - if (!res) - tty->driver_data = info; - - return res; -} - -static void smd_tty_port_shutdown(struct tty_port *tport) -{ - struct smd_tty_info *info = container_of(tport, struct smd_tty_info, - port); - - if (info->ch) { - smd_close(info->ch); - info->ch = 0; - } -} - -static int smd_tty_open(struct tty_struct *tty, struct file *f) -{ - struct smd_tty_info *info = smd_tty + tty->index; - - return tty_port_open(&info->port, tty, f); -} - -static void smd_tty_close(struct tty_struct *tty, struct file *f) -{ - struct smd_tty_info *info = tty->driver_data; - - tty_port_close(&info->port, tty, f); -} - -static int smd_tty_write(struct tty_struct *tty, - const unsigned char *buf, int len) -{ - struct smd_tty_info *info = tty->driver_data; - int avail; - - /* if we're writing to a packet channel we will - ** never be able to write more data than there - ** is currently space for - */ - avail = smd_write_avail(info->ch); - if (len > avail) - len = avail; - - return smd_write(info->ch, buf, len); -} - -static int smd_tty_write_room(struct tty_struct *tty) -{ - struct smd_tty_info *info = tty->driver_data; - return smd_write_avail(info->ch); -} - -static int smd_tty_chars_in_buffer(struct tty_struct *tty) -{ - struct smd_tty_info *info = tty->driver_data; - return smd_read_avail(info->ch); -} - -static void smd_tty_unthrottle(struct tty_struct *tty) -{ - struct smd_tty_info *info = tty->driver_data; - smd_kick(info->ch); -} - -static const struct tty_port_operations smd_tty_port_ops = { - .shutdown = smd_tty_port_shutdown, - .activate = smd_tty_port_activate, -}; - -static const struct tty_operations smd_tty_ops = { - .open = smd_tty_open, - .close = smd_tty_close, - .write = smd_tty_write, - .write_room = smd_tty_write_room, - .chars_in_buffer = smd_tty_chars_in_buffer, - .unthrottle = smd_tty_unthrottle, -}; - -static struct tty_driver *smd_tty_driver; - -static int __init smd_tty_init(void) -{ - int ret, i; - - smd_tty_driver = alloc_tty_driver(MAX_SMD_TTYS); - if (smd_tty_driver == 0) - return -ENOMEM; - - smd_tty_driver->driver_name = "smd_tty_driver"; - smd_tty_driver->name = "smd"; - smd_tty_driver->major = 0; - smd_tty_driver->minor_start = 0; - smd_tty_driver->type = TTY_DRIVER_TYPE_SERIAL; - smd_tty_driver->subtype = SERIAL_TYPE_NORMAL; - smd_tty_driver->init_termios = tty_std_termios; - smd_tty_driver->init_termios.c_iflag = 0; - smd_tty_driver->init_termios.c_oflag = 0; - smd_tty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; - smd_tty_driver->init_termios.c_lflag = 0; - smd_tty_driver->flags = TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_set_operations(smd_tty_driver, &smd_tty_ops); - - ret = tty_register_driver(smd_tty_driver); - if (ret) - return ret; - - for (i = 0; i < smd_tty_channels_len; i++) { - struct tty_port *port = &smd_tty[smd_tty_channels[i].id].port; - tty_port_init(port); - port->ops = &smd_tty_port_ops; - tty_port_register_device(port, smd_tty_driver, - smd_tty_channels[i].id, NULL); - } - - return 0; -} - -module_init(smd_tty_init); diff --git a/kernel/drivers/tty/serial/mux.c b/kernel/drivers/tty/serial/mux.c index dd26511ad..8a4be4b73 100644 --- a/kernel/drivers/tty/serial/mux.c +++ b/kernel/drivers/tty/serial/mux.c @@ -412,19 +412,14 @@ static int mux_console_setup(struct console *co, char *options) return 0; } -struct tty_driver *mux_console_device(struct console *co, int *index) -{ - *index = co->index; - return mux_driver.tty_driver; -} - static struct console mux_console = { .name = "ttyB", .write = mux_console_write, - .device = mux_console_device, + .device = uart_console_device, .setup = mux_console_setup, .flags = CON_ENABLED | CON_PRINTBUFFER, .index = 0, + .data = &mux_driver, }; #define MUX_CONSOLE &mux_console diff --git a/kernel/drivers/tty/serial/mxs-auart.c b/kernel/drivers/tty/serial/mxs-auart.c index f7e5825b5..cd0414bbe 100644 --- a/kernel/drivers/tty/serial/mxs-auart.c +++ b/kernel/drivers/tty/serial/mxs-auart.c @@ -100,6 +100,8 @@ #define AUART_CTRL2_TXE (1 << 8) #define AUART_CTRL2_UARTEN (1 << 0) +#define AUART_LINECTRL_BAUD_DIV_MAX 0x003fffc0 +#define AUART_LINECTRL_BAUD_DIV_MIN 0x000000ec #define AUART_LINECTRL_BAUD_DIVINT_SHIFT 16 #define AUART_LINECTRL_BAUD_DIVINT_MASK 0xffff0000 #define AUART_LINECTRL_BAUD_DIVINT(v) (((v) & 0xffff) << 16) @@ -169,7 +171,7 @@ struct mxs_auart_port { bool ms_irq_enabled; }; -static struct platform_device_id mxs_auart_devtype[] = { +static const struct platform_device_id mxs_auart_devtype[] = { { .name = "mxs-auart-imx23", .driver_data = IMX23_AUART }, { .name = "mxs-auart-imx28", .driver_data = IMX28_AUART }, { /* sentinel */ } @@ -659,7 +661,7 @@ static void mxs_auart_settermios(struct uart_port *u, { struct mxs_auart_port *s = to_auart_port(u); u32 bm, ctrl, ctrl2, div; - unsigned int cflag, baud; + unsigned int cflag, baud, baud_min, baud_max; cflag = termios->c_cflag; @@ -752,7 +754,9 @@ static void mxs_auart_settermios(struct uart_port *u, } /* set baud rate */ - baud = uart_get_baud_rate(u, termios, old, 0, u->uartclk); + baud_min = DIV_ROUND_UP(u->uartclk * 32, AUART_LINECTRL_BAUD_DIV_MAX); + baud_max = u->uartclk * 32 / AUART_LINECTRL_BAUD_DIV_MIN; + baud = uart_get_baud_rate(u, termios, old, baud_min, baud_max); div = u->uartclk * 32 / baud; ctrl |= AUART_LINECTRL_BAUD_DIVFRAC(div & 0x3F); ctrl |= AUART_LINECTRL_BAUD_DIVINT(div >> 6); @@ -842,7 +846,7 @@ static irqreturn_t mxs_auart_irq_handle(int irq, void *context) return IRQ_HANDLED; } -static void mxs_auart_reset(struct uart_port *u) +static void mxs_auart_reset_deassert(struct uart_port *u) { int i; unsigned int reg; @@ -858,6 +862,30 @@ static void mxs_auart_reset(struct uart_port *u) writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); } +static void mxs_auart_reset_assert(struct uart_port *u) +{ + int i; + u32 reg; + + reg = readl(u->membase + AUART_CTRL0); + /* if already in reset state, keep it untouched */ + if (reg & AUART_CTRL0_SFTRST) + return; + + writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); + writel(AUART_CTRL0_SFTRST, u->membase + AUART_CTRL0_SET); + + for (i = 0; i < 1000; i++) { + reg = readl(u->membase + AUART_CTRL0); + /* reset is finished when the clock is gated */ + if (reg & AUART_CTRL0_CLKGATE) + return; + udelay(10); + } + + dev_err(u->dev, "Failed to reset the unit."); +} + static int mxs_auart_startup(struct uart_port *u) { int ret; @@ -867,7 +895,13 @@ static int mxs_auart_startup(struct uart_port *u) if (ret) return ret; - writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); + if (uart_console(u)) { + writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_CLR); + } else { + /* reset the unit to a well known state */ + mxs_auart_reset_assert(u); + mxs_auart_reset_deassert(u); + } writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_SET); @@ -899,12 +933,14 @@ static void mxs_auart_shutdown(struct uart_port *u) if (auart_dma_enabled(s)) mxs_auart_dma_exit(s); - writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR); - - writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, - u->membase + AUART_INTR_CLR); - - writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET); + if (uart_console(u)) { + writel(AUART_CTRL2_UARTEN, u->membase + AUART_CTRL2_CLR); + writel(AUART_INTR_RXIEN | AUART_INTR_RTIEN | AUART_INTR_CTSMIEN, + u->membase + AUART_INTR_CLR); + writel(AUART_CTRL0_CLKGATE, u->membase + AUART_CTRL0_SET); + } else { + mxs_auart_reset_assert(u); + } clk_disable_unprepare(s->clk); } @@ -1160,7 +1196,7 @@ static int mxs_auart_init_gpios(struct mxs_auart_port *s, struct device *dev) enum mctrl_gpio_idx i; struct gpio_desc *gpiod; - s->gpios = mctrl_gpio_init(dev, 0); + s->gpios = mctrl_gpio_init_noauto(dev, 0); if (IS_ERR(s->gpios)) return PTR_ERR(s->gpios); @@ -1291,7 +1327,7 @@ static int mxs_auart_probe(struct platform_device *pdev) auart_port[s->port.line] = s; - mxs_auart_reset(&s->port); + mxs_auart_reset_deassert(&s->port); ret = uart_add_one_port(&auart_driver, &s->port); if (ret) diff --git a/kernel/drivers/tty/serial/of_serial.c b/kernel/drivers/tty/serial/of_serial.c index 137381e64..de5029649 100644 --- a/kernel/drivers/tty/serial/of_serial.c +++ b/kernel/drivers/tty/serial/of_serial.c @@ -21,6 +21,10 @@ #include <linux/nwpserial.h> #include <linux/clk.h> +#ifdef CONFIG_SERIAL_8250_MODULE +#define CONFIG_SERIAL_8250 CONFIG_SERIAL_8250_MODULE +#endif + #include "8250/8250.h" struct of_serial_info { @@ -67,14 +71,17 @@ static int of_platform_serial_setup(struct platform_device *ofdev, if (of_property_read_u32(np, "clock-frequency", &clk)) { /* Get clk rate through clk driver if present */ - info->clk = clk_get(&ofdev->dev, NULL); + info->clk = devm_clk_get(&ofdev->dev, NULL); if (IS_ERR(info->clk)) { dev_warn(&ofdev->dev, "clk or clock-frequency not defined\n"); return PTR_ERR(info->clk); } - clk_prepare_enable(info->clk); + ret = clk_prepare_enable(info->clk); + if (ret < 0) + return ret; + clk = clk_get_rate(info->clk); } /* If current-speed was set, then try not to change it. */ @@ -147,6 +154,11 @@ static int of_platform_serial_setup(struct platform_device *ofdev, break; } + if (IS_ENABLED(CONFIG_SERIAL_8250_FSL) && + (of_device_is_compatible(np, "fsl,ns16550") || + of_device_is_compatible(np, "fsl,16550-FIFO64"))) + port->handle_irq = fsl8250_handle_irq; + return 0; out: if (info->clk) @@ -188,7 +200,6 @@ static int of_platform_serial_probe(struct platform_device *ofdev) { struct uart_8250_port port8250; memset(&port8250, 0, sizeof(port8250)); - port.type = port_type; port8250.port = port; if (port.fifosize) @@ -348,6 +359,7 @@ static const struct of_device_id of_platform_serial_table[] = { #endif { /* end of list */ }, }; +MODULE_DEVICE_TABLE(of, of_platform_serial_table); static struct platform_driver of_platform_serial_driver = { .driver = { diff --git a/kernel/drivers/tty/serial/omap-serial.c b/kernel/drivers/tty/serial/omap-serial.c index f9d192f67..9745fb8b7 100644 --- a/kernel/drivers/tty/serial/omap-serial.c +++ b/kernel/drivers/tty/serial/omap-serial.c @@ -38,6 +38,7 @@ #include <linux/serial_core.h> #include <linux/irq.h> #include <linux/pm_runtime.h> +#include <linux/pm_wakeirq.h> #include <linux/of.h> #include <linux/of_irq.h> #include <linux/gpio.h> @@ -160,7 +161,6 @@ struct uart_omap_port { unsigned long port_activity; int context_loss_cnt; u32 errata; - u8 wakeups_enabled; u32 features; int rts_gpio; @@ -199,6 +199,7 @@ static inline void serial_omap_clear_fifos(struct uart_omap_port *up) serial_out(up, UART_FCR, 0); } +#ifdef CONFIG_PM static int serial_omap_get_context_loss_count(struct uart_omap_port *up) { struct omap_uart_port_info *pdata = dev_get_platdata(up->dev); @@ -209,33 +210,17 @@ static int serial_omap_get_context_loss_count(struct uart_omap_port *up) return pdata->get_context_loss_count(up->dev); } -static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, - bool enable) -{ - if (!up->wakeirq) - return; - - if (enable) - enable_irq(up->wakeirq); - else - disable_irq_nosync(up->wakeirq); -} - +/* REVISIT: Remove this when omap3 boots in device tree only mode */ static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) { struct omap_uart_port_info *pdata = dev_get_platdata(up->dev); - if (enable == up->wakeups_enabled) - return; - - serial_omap_enable_wakeirq(up, enable); - up->wakeups_enabled = enable; - if (!pdata || !pdata->enable_wakeup) return; pdata->enable_wakeup(up->dev, enable); } +#endif /* CONFIG_PM */ /* * Calculate the absolute difference between the desired and actual baud @@ -750,13 +735,11 @@ static int serial_omap_startup(struct uart_port *port) /* Optional wake-up IRQ */ if (up->wakeirq) { - retval = request_irq(up->wakeirq, serial_omap_irq, - up->port.irqflags, up->name, up); + retval = dev_pm_set_dedicated_wake_irq(up->dev, up->wakeirq); if (retval) { free_irq(up->port.irq, up); return retval; } - disable_irq(up->wakeirq); } dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); @@ -845,8 +828,7 @@ static void serial_omap_shutdown(struct uart_port *port) pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); free_irq(up->port.irq, up); - if (up->wakeirq) - free_irq(up->wakeirq, up); + dev_pm_clear_wake_irq(up->dev); } static void serial_omap_uart_qos_work(struct work_struct *work) @@ -1139,13 +1121,6 @@ serial_omap_pm(struct uart_port *port, unsigned int state, serial_out(up, UART_EFR, efr); serial_out(up, UART_LCR, 0); - if (!device_may_wakeup(up->dev)) { - if (!state) - pm_runtime_forbid(up->dev); - else - pm_runtime_allow(up->dev); - } - pm_runtime_mark_last_busy(up->dev); pm_runtime_put_autosuspend(up->dev); } @@ -1364,7 +1339,7 @@ static inline void serial_omap_add_console_port(struct uart_omap_port *up) /* Enable or disable the rs485 support */ static int -serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) +serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) { struct uart_omap_port *up = to_uart_omap_port(port); unsigned int mode; @@ -1377,8 +1352,12 @@ serial_omap_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) up->ier = 0; serial_out(up, UART_IER, 0); + /* Clamp the delays to [0, 100ms] */ + rs485->delay_rts_before_send = min(rs485->delay_rts_before_send, 100U); + rs485->delay_rts_after_send = min(rs485->delay_rts_after_send, 100U); + /* store new config */ - port->rs485 = *rs485conf; + port->rs485 = *rs485; /* * Just as a precaution, only allow rs485 diff --git a/kernel/drivers/tty/serial/samsung.c b/kernel/drivers/tty/serial/samsung.c index 1e0d9b8c4..d72cd736b 100644 --- a/kernel/drivers/tty/serial/samsung.c +++ b/kernel/drivers/tty/serial/samsung.c @@ -53,7 +53,6 @@ #include "samsung.h" #if defined(CONFIG_SERIAL_SAMSUNG_DEBUG) && \ - defined(CONFIG_DEBUG_LL) && \ !defined(MODULE) extern void printascii(const char *); @@ -341,7 +340,7 @@ static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport) s3c24xx_serial_start_tx_dma(ourport, count); } -void s3c24xx_serial_start_tx(struct uart_port *port) +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; @@ -386,32 +385,6 @@ static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport, } } -static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport, - unsigned long ufstat); - -static void uart_rx_drain_fifo(struct s3c24xx_uart_port *ourport) -{ - struct uart_port *port = &ourport->port; - struct tty_port *tty = &port->state->port; - unsigned int ch, ufstat; - unsigned int count; - - ufstat = rd_regl(port, S3C2410_UFSTAT); - count = s3c24xx_serial_rx_fifocnt(ourport, ufstat); - - if (!count) - return; - - while (count-- > 0) { - ch = rd_regb(port, S3C2410_URXH); - - ourport->port.icount.rx++; - tty_insert_flip_char(tty, ch, TTY_NORMAL); - } - - tty_flip_buffer_push(tty); -} - static void s3c24xx_serial_stop_rx(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); @@ -574,7 +547,9 @@ static void enable_rx_pio(struct s3c24xx_uart_port *ourport) ourport->rx_mode = S3C24XX_RX_PIO; } -static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id) +static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport); + +static irqreturn_t s3c24xx_serial_rx_chars_dma(void *dev_id) { unsigned int utrstat, ufstat, received; struct s3c24xx_uart_port *ourport = dev_id; @@ -607,7 +582,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id) enable_rx_pio(ourport); } - uart_rx_drain_fifo(ourport); + s3c24xx_serial_rx_drain_fifo(ourport); if (tty) { tty_flip_buffer_push(t); @@ -622,16 +597,12 @@ finish: return IRQ_HANDLED; } -static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id) +static void s3c24xx_serial_rx_drain_fifo(struct s3c24xx_uart_port *ourport) { - struct s3c24xx_uart_port *ourport = dev_id; struct uart_port *port = &ourport->port; unsigned int ufcon, ch, flag, ufstat, uerstat; - unsigned long flags; int max_count = port->fifosize; - spin_lock_irqsave(&port->lock, flags); - while (max_count-- > 0) { ufcon = rd_regl(port, S3C2410_UFCON); ufstat = rd_regl(port, S3C2410_UFSTAT); @@ -655,9 +626,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id) ufcon |= S3C2410_UFCON_RESETRX; wr_regl(port, S3C2410_UFCON, ufcon); rx_enabled(port) = 1; - spin_unlock_irqrestore(&port->lock, - flags); - goto out; + return; } continue; } @@ -677,7 +646,7 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id) dbg("break!\n"); port->icount.brk++; if (uart_handle_break(port)) - goto ignore_char; + continue; /* Ignore character */ } if (uerstat & S3C2410_UERSTAT_FRAME) @@ -697,19 +666,25 @@ static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id) } if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; + continue; /* Ignore character */ uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag); - -ignore_char: - continue; } - spin_unlock_irqrestore(&port->lock, flags); tty_flip_buffer_push(&port->state->port); +} + +static irqreturn_t s3c24xx_serial_rx_chars_pio(void *dev_id) +{ + struct s3c24xx_uart_port *ourport = dev_id; + struct uart_port *port = &ourport->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + s3c24xx_serial_rx_drain_fifo(ourport); + spin_unlock_irqrestore(&port->lock, flags); -out: return IRQ_HANDLED; } @@ -719,8 +694,8 @@ static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id) struct s3c24xx_uart_port *ourport = dev_id; if (ourport->dma && ourport->dma->rx_chan) - return s3c24xx_serial_rx_chars_dma(irq, dev_id); - return s3c24xx_serial_rx_chars_pio(irq, dev_id); + return s3c24xx_serial_rx_chars_dma(dev_id); + return s3c24xx_serial_rx_chars_pio(dev_id); } static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id) @@ -2352,7 +2327,7 @@ static struct s3c24xx_serial_drv_data exynos5433_serial_drv_data = { #define EXYNOS5433_SERIAL_DRV_DATA (kernel_ulong_t)NULL #endif -static struct platform_device_id s3c24xx_serial_driver_ids[] = { +static const struct platform_device_id s3c24xx_serial_driver_ids[] = { { .name = "s3c2410-uart", .driver_data = S3C2410_SERIAL_DRV_DATA, diff --git a/kernel/drivers/tty/serial/sc16is7xx.c b/kernel/drivers/tty/serial/sc16is7xx.c index 468354ef7..7d5ee8a13 100644 --- a/kernel/drivers/tty/serial/sc16is7xx.c +++ b/kernel/drivers/tty/serial/sc16is7xx.c @@ -11,6 +11,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/bitops.h> #include <linux/clk.h> #include <linux/delay.h> @@ -25,9 +27,11 @@ #include <linux/serial.h> #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/spi/spi.h> #include <linux/uaccess.h> #define SC16IS7XX_NAME "sc16is7xx" +#define SC16IS7XX_MAX_DEVS 8 /* SC16IS7XX register definitions */ #define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */ @@ -300,34 +304,62 @@ struct sc16is7xx_devtype { int nr_uart; }; +#define SC16IS7XX_RECONF_MD (1 << 0) +#define SC16IS7XX_RECONF_IER (1 << 1) +#define SC16IS7XX_RECONF_RS485 (1 << 2) + +struct sc16is7xx_one_config { + unsigned int flags; + u8 ier_clear; +}; + struct sc16is7xx_one { struct uart_port port; - struct work_struct tx_work; - struct work_struct md_work; + u8 line; + struct kthread_work tx_work; + struct kthread_work reg_work; + struct sc16is7xx_one_config config; }; struct sc16is7xx_port { - struct uart_driver uart; - struct sc16is7xx_devtype *devtype; + const struct sc16is7xx_devtype *devtype; struct regmap *regmap; - struct mutex mutex; struct clk *clk; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio; #endif unsigned char buf[SC16IS7XX_FIFO_SIZE]; + struct kthread_worker kworker; + struct task_struct *kworker_task; + struct kthread_work irq_work; struct sc16is7xx_one p[0]; }; +static unsigned long sc16is7xx_lines; + +static struct uart_driver sc16is7xx_uart = { + .owner = THIS_MODULE, + .dev_name = "ttySC", + .nr = SC16IS7XX_MAX_DEVS, +}; + +#define to_sc16is7xx_port(p,e) ((container_of((p), struct sc16is7xx_port, e))) #define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e))) +static int sc16is7xx_line(struct uart_port *port) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); + + return one->line; +} + static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); unsigned int val = 0; + const u8 line = sc16is7xx_line(port); - regmap_read(s->regmap, - (reg << SC16IS7XX_REG_SHIFT) | port->line, &val); + regmap_read(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, &val); return val; } @@ -335,21 +367,55 @@ static u8 sc16is7xx_port_read(struct uart_port *port, u8 reg) static void sc16is7xx_port_write(struct uart_port *port, u8 reg, u8 val) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + const u8 line = sc16is7xx_line(port); + + regmap_write(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, val); +} + +static void sc16is7xx_fifo_read(struct uart_port *port, unsigned int rxlen) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + const u8 line = sc16is7xx_line(port); + u8 addr = (SC16IS7XX_RHR_REG << SC16IS7XX_REG_SHIFT) | line; + + regcache_cache_bypass(s->regmap, true); + regmap_raw_read(s->regmap, addr, s->buf, rxlen); + regcache_cache_bypass(s->regmap, false); +} + +static void sc16is7xx_fifo_write(struct uart_port *port, u8 to_send) +{ + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + const u8 line = sc16is7xx_line(port); + u8 addr = (SC16IS7XX_THR_REG << SC16IS7XX_REG_SHIFT) | line; - regmap_write(s->regmap, - (reg << SC16IS7XX_REG_SHIFT) | port->line, val); + regcache_cache_bypass(s->regmap, true); + regmap_raw_write(s->regmap, addr, s->buf, to_send); + regcache_cache_bypass(s->regmap, false); } static void sc16is7xx_port_update(struct uart_port *port, u8 reg, u8 mask, u8 val) { struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + const u8 line = sc16is7xx_line(port); - regmap_update_bits(s->regmap, - (reg << SC16IS7XX_REG_SHIFT) | port->line, + regmap_update_bits(s->regmap, (reg << SC16IS7XX_REG_SHIFT) | line, mask, val); } +static int sc16is7xx_alloc_line(void) +{ + int i; + + BUILD_BUG_ON(SC16IS7XX_MAX_DEVS > BITS_PER_LONG); + + for (i = 0; i < SC16IS7XX_MAX_DEVS; i++) + if (!test_and_set_bit(i, &sc16is7xx_lines)) + break; + + return i; +} static void sc16is7xx_power(struct uart_port *port, int on) { @@ -474,7 +540,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, if (unlikely(rxlen >= sizeof(s->buf))) { dev_warn_ratelimited(port->dev, - "Port %i: Possible RX FIFO overrun: %d\n", + "ttySC%i: Possible RX FIFO overrun: %d\n", port->line, rxlen); port->icount.buf_overrun++; /* Ensure sanity of RX level */ @@ -494,10 +560,7 @@ static void sc16is7xx_handle_rx(struct uart_port *port, unsigned int rxlen, s->buf[0] = sc16is7xx_port_read(port, SC16IS7XX_RHR_REG); bytes_read = 1; } else { - regcache_cache_bypass(s->regmap, true); - regmap_raw_read(s->regmap, SC16IS7XX_RHR_REG, - s->buf, rxlen); - regcache_cache_bypass(s->regmap, false); + sc16is7xx_fifo_read(port, rxlen); bytes_read = rxlen; } @@ -577,9 +640,8 @@ static void sc16is7xx_handle_tx(struct uart_port *port) s->buf[i] = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); } - regcache_cache_bypass(s->regmap, true); - regmap_raw_write(s->regmap, SC16IS7XX_THR_REG, s->buf, to_send); - regcache_cache_bypass(s->regmap, false); + + sc16is7xx_fifo_write(port, to_send); } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) @@ -615,94 +677,126 @@ static void sc16is7xx_port_irq(struct sc16is7xx_port *s, int portno) !!(msr & SC16IS7XX_MSR_CTS_BIT)); break; case SC16IS7XX_IIR_THRI_SRC: - mutex_lock(&s->mutex); sc16is7xx_handle_tx(port); - mutex_unlock(&s->mutex); break; default: dev_err_ratelimited(port->dev, - "Port %i: Unexpected interrupt: %x", + "ttySC%i: Unexpected interrupt: %x", port->line, iir); break; } } while (1); } -static irqreturn_t sc16is7xx_ist(int irq, void *dev_id) +static void sc16is7xx_ist(struct kthread_work *ws) { - struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; + struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work); int i; - for (i = 0; i < s->uart.nr; ++i) + for (i = 0; i < s->devtype->nr_uart; ++i) sc16is7xx_port_irq(s, i); +} + +static irqreturn_t sc16is7xx_irq(int irq, void *dev_id) +{ + struct sc16is7xx_port *s = (struct sc16is7xx_port *)dev_id; + + queue_kthread_work(&s->kworker, &s->irq_work); return IRQ_HANDLED; } -static void sc16is7xx_wq_proc(struct work_struct *ws) +static void sc16is7xx_tx_proc(struct kthread_work *ws) { - struct sc16is7xx_one *one = to_sc16is7xx_one(ws, tx_work); - struct sc16is7xx_port *s = dev_get_drvdata(one->port.dev); + struct uart_port *port = &(to_sc16is7xx_one(ws, tx_work)->port); - mutex_lock(&s->mutex); - sc16is7xx_handle_tx(&one->port); - mutex_unlock(&s->mutex); + if ((port->rs485.flags & SER_RS485_ENABLED) && + (port->rs485.delay_rts_before_send > 0)) + msleep(port->rs485.delay_rts_before_send); + + sc16is7xx_handle_tx(port); } -static void sc16is7xx_stop_tx(struct uart_port* port) +static void sc16is7xx_reconf_rs485(struct uart_port *port) { - struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - struct circ_buf *xmit = &one->port.state->xmit; - - /* handle rs485 */ - if (port->rs485.flags & SER_RS485_ENABLED) { - /* do nothing if current tx not yet completed */ - int lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); - if (!(lsr & SC16IS7XX_LSR_TEMT_BIT)) - return; - - if (uart_circ_empty(xmit) && - (port->rs485.delay_rts_after_send > 0)) - mdelay(port->rs485.delay_rts_after_send); + const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT | + SC16IS7XX_EFCR_RTS_INVERT_BIT; + u32 efcr = 0; + struct serial_rs485 *rs485 = &port->rs485; + unsigned long irqflags; + + spin_lock_irqsave(&port->lock, irqflags); + if (rs485->flags & SER_RS485_ENABLED) { + efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT; + + if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT; } + spin_unlock_irqrestore(&port->lock, irqflags); - sc16is7xx_port_update(port, SC16IS7XX_IER_REG, - SC16IS7XX_IER_THRI_BIT, - 0); + sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr); +} + +static void sc16is7xx_reg_proc(struct kthread_work *ws) +{ + struct sc16is7xx_one *one = to_sc16is7xx_one(ws, reg_work); + struct sc16is7xx_one_config config; + unsigned long irqflags; + + spin_lock_irqsave(&one->port.lock, irqflags); + config = one->config; + memset(&one->config, 0, sizeof(one->config)); + spin_unlock_irqrestore(&one->port.lock, irqflags); + + if (config.flags & SC16IS7XX_RECONF_MD) + sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, + SC16IS7XX_MCR_LOOP_BIT, + (one->port.mctrl & TIOCM_LOOP) ? + SC16IS7XX_MCR_LOOP_BIT : 0); + + if (config.flags & SC16IS7XX_RECONF_IER) + sc16is7xx_port_update(&one->port, SC16IS7XX_IER_REG, + config.ier_clear, 0); + + if (config.flags & SC16IS7XX_RECONF_RS485) + sc16is7xx_reconf_rs485(&one->port); } -static void sc16is7xx_stop_rx(struct uart_port* port) +static void sc16is7xx_ier_clear(struct uart_port *port, u8 bit) { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - one->port.read_status_mask &= ~SC16IS7XX_LSR_DR_BIT; - sc16is7xx_port_update(port, SC16IS7XX_IER_REG, - SC16IS7XX_LSR_DR_BIT, - 0); + one->config.flags |= SC16IS7XX_RECONF_IER; + one->config.ier_clear |= bit; + queue_kthread_work(&s->kworker, &one->reg_work); +} + +static void sc16is7xx_stop_tx(struct uart_port *port) +{ + sc16is7xx_ier_clear(port, SC16IS7XX_IER_THRI_BIT); +} + +static void sc16is7xx_stop_rx(struct uart_port *port) +{ + sc16is7xx_ier_clear(port, SC16IS7XX_IER_RDI_BIT); } static void sc16is7xx_start_tx(struct uart_port *port) { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - /* handle rs485 */ - if ((port->rs485.flags & SER_RS485_ENABLED) && - (port->rs485.delay_rts_before_send > 0)) { - mdelay(port->rs485.delay_rts_before_send); - } - - if (!work_pending(&one->tx_work)) - schedule_work(&one->tx_work); + queue_kthread_work(&s->kworker, &one->tx_work); } static unsigned int sc16is7xx_tx_empty(struct uart_port *port) { - unsigned int lvl, lsr; + unsigned int lsr; - lvl = sc16is7xx_port_read(port, SC16IS7XX_TXLVL_REG); lsr = sc16is7xx_port_read(port, SC16IS7XX_LSR_REG); - return ((lsr & SC16IS7XX_LSR_THRE_BIT) && !lvl) ? TIOCSER_TEMT : 0; + return (lsr & SC16IS7XX_LSR_TEMT_BIT) ? TIOCSER_TEMT : 0; } static unsigned int sc16is7xx_get_mctrl(struct uart_port *port) @@ -713,21 +807,13 @@ static unsigned int sc16is7xx_get_mctrl(struct uart_port *port) return TIOCM_DSR | TIOCM_CAR; } -static void sc16is7xx_md_proc(struct work_struct *ws) -{ - struct sc16is7xx_one *one = to_sc16is7xx_one(ws, md_work); - - sc16is7xx_port_update(&one->port, SC16IS7XX_MCR_REG, - SC16IS7XX_MCR_LOOP_BIT, - (one->port.mctrl & TIOCM_LOOP) ? - SC16IS7XX_MCR_LOOP_BIT : 0); -} - static void sc16is7xx_set_mctrl(struct uart_port *port, unsigned int mctrl) { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); - schedule_work(&one->md_work); + one->config.flags |= SC16IS7XX_RECONF_MD; + queue_kthread_work(&s->kworker, &one->reg_work); } static void sc16is7xx_break_ctl(struct uart_port *port, int break_state) @@ -831,9 +917,8 @@ static void sc16is7xx_set_termios(struct uart_port *port, static int sc16is7xx_config_rs485(struct uart_port *port, struct serial_rs485 *rs485) { - const u32 mask = SC16IS7XX_EFCR_AUTO_RS485_BIT | - SC16IS7XX_EFCR_RTS_INVERT_BIT; - u32 efcr = 0; + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + struct sc16is7xx_one *one = to_sc16is7xx_one(port, port); if (rs485->flags & SER_RS485_ENABLED) { bool rts_during_rx, rts_during_tx; @@ -841,21 +926,23 @@ static int sc16is7xx_config_rs485(struct uart_port *port, rts_during_rx = rs485->flags & SER_RS485_RTS_AFTER_SEND; rts_during_tx = rs485->flags & SER_RS485_RTS_ON_SEND; - efcr |= SC16IS7XX_EFCR_AUTO_RS485_BIT; - - if (!rts_during_rx && rts_during_tx) - /* default */; - else if (rts_during_rx && !rts_during_tx) - efcr |= SC16IS7XX_EFCR_RTS_INVERT_BIT; - else + if (rts_during_rx == rts_during_tx) dev_err(port->dev, "unsupported RTS signalling on_send:%d after_send:%d - exactly one of RS485 RTS flags should be set\n", rts_during_tx, rts_during_rx); - } - sc16is7xx_port_update(port, SC16IS7XX_EFCR_REG, mask, efcr); + /* + * RTS signal is handled by HW, it's timing can't be influenced. + * However, it's sometimes useful to delay TX even without RTS + * control therefore we try to handle .delay_rts_before_send. + */ + if (rs485->delay_rts_after_send) + return -EINVAL; + } port->rs485 = *rs485; + one->config.flags |= SC16IS7XX_RECONF_RS485; + queue_kthread_work(&s->kworker, &one->reg_work); return 0; } @@ -916,6 +1003,8 @@ static int sc16is7xx_startup(struct uart_port *port) static void sc16is7xx_shutdown(struct uart_port *port) { + struct sc16is7xx_port *s = dev_get_drvdata(port->dev); + /* Disable all interrupts */ sc16is7xx_port_write(port, SC16IS7XX_IER_REG, 0); /* Disable TX/RX */ @@ -926,6 +1015,8 @@ static void sc16is7xx_shutdown(struct uart_port *port) SC16IS7XX_EFCR_TXDISABLE_BIT); sc16is7xx_power(port, 0); + + flush_kthread_worker(&s->kworker); } static const char *sc16is7xx_type(struct uart_port *port) @@ -1040,9 +1131,10 @@ static int sc16is7xx_gpio_direction_output(struct gpio_chip *chip, #endif static int sc16is7xx_probe(struct device *dev, - struct sc16is7xx_devtype *devtype, + const struct sc16is7xx_devtype *devtype, struct regmap *regmap, int irq, unsigned long flags) { + struct sched_param sched_param = { .sched_priority = MAX_RT_PRIO / 2 }; unsigned long freq, *pfreq = dev_get_platdata(dev); int i, ret; struct sc16is7xx_port *s; @@ -1074,15 +1166,15 @@ static int sc16is7xx_probe(struct device *dev, s->devtype = devtype; dev_set_drvdata(dev, s); - /* Register UART driver */ - s->uart.owner = THIS_MODULE; - s->uart.dev_name = "ttySC"; - s->uart.nr = devtype->nr_uart; - ret = uart_register_driver(&s->uart); - if (ret) { - dev_err(dev, "Registering UART driver failed\n"); + init_kthread_worker(&s->kworker); + init_kthread_work(&s->irq_work, sc16is7xx_ist); + s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker, + "sc16is7xx"); + if (IS_ERR(s->kworker_task)) { + ret = PTR_ERR(s->kworker_task); goto out_clk; } + sched_setscheduler(s->kworker_task, SCHED_FIFO, &sched_param); #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) { @@ -1099,15 +1191,13 @@ static int sc16is7xx_probe(struct device *dev, s->gpio.can_sleep = 1; ret = gpiochip_add(&s->gpio); if (ret) - goto out_uart; + goto out_thread; } #endif - mutex_init(&s->mutex); - for (i = 0; i < devtype->nr_uart; ++i) { + s->p[i].line = i; /* Initialize port data */ - s->p[i].port.line = i; s->p[i].port.dev = dev; s->p[i].port.irq = irq; s->p[i].port.type = PORT_SC16IS7XX; @@ -1117,40 +1207,46 @@ static int sc16is7xx_probe(struct device *dev, s->p[i].port.uartclk = freq; s->p[i].port.rs485_config = sc16is7xx_config_rs485; s->p[i].port.ops = &sc16is7xx_ops; + s->p[i].port.line = sc16is7xx_alloc_line(); + if (s->p[i].port.line >= SC16IS7XX_MAX_DEVS) { + ret = -ENOMEM; + goto out_ports; + } + /* Disable all interrupts */ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_IER_REG, 0); /* Disable TX/RX */ sc16is7xx_port_write(&s->p[i].port, SC16IS7XX_EFCR_REG, SC16IS7XX_EFCR_RXDISABLE_BIT | SC16IS7XX_EFCR_TXDISABLE_BIT); - /* Initialize queue for start TX */ - INIT_WORK(&s->p[i].tx_work, sc16is7xx_wq_proc); - /* Initialize queue for changing mode */ - INIT_WORK(&s->p[i].md_work, sc16is7xx_md_proc); + /* Initialize kthread work structs */ + init_kthread_work(&s->p[i].tx_work, sc16is7xx_tx_proc); + init_kthread_work(&s->p[i].reg_work, sc16is7xx_reg_proc); /* Register port */ - uart_add_one_port(&s->uart, &s->p[i].port); + uart_add_one_port(&sc16is7xx_uart, &s->p[i].port); /* Go to suspend mode */ sc16is7xx_power(&s->p[i].port, 0); } /* Setup interrupt */ - ret = devm_request_threaded_irq(dev, irq, NULL, sc16is7xx_ist, - IRQF_ONESHOT | flags, dev_name(dev), s); + ret = devm_request_irq(dev, irq, sc16is7xx_irq, + flags, dev_name(dev), s); if (!ret) return 0; - for (i = 0; i < s->uart.nr; i++) - uart_remove_one_port(&s->uart, &s->p[i].port); - - mutex_destroy(&s->mutex); +out_ports: + for (i--; i >= 0; i--) { + uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); + clear_bit(s->p[i].port.line, &sc16is7xx_lines); + } #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) gpiochip_remove(&s->gpio); -out_uart: +out_thread: #endif - uart_unregister_driver(&s->uart); + kthread_stop(s->kworker_task); out_clk: if (!IS_ERR(s->clk)) @@ -1169,15 +1265,15 @@ static int sc16is7xx_remove(struct device *dev) gpiochip_remove(&s->gpio); #endif - for (i = 0; i < s->uart.nr; i++) { - cancel_work_sync(&s->p[i].tx_work); - cancel_work_sync(&s->p[i].md_work); - uart_remove_one_port(&s->uart, &s->p[i].port); + for (i = 0; i < s->devtype->nr_uart; i++) { + uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); + clear_bit(s->p[i].port.line, &sc16is7xx_lines); sc16is7xx_power(&s->p[i].port, 0); } - mutex_destroy(&s->mutex); - uart_unregister_driver(&s->uart); + flush_kthread_worker(&s->kworker); + kthread_stop(s->kworker_task); + if (!IS_ERR(s->clk)) clk_disable_unprepare(s->clk); @@ -1204,10 +1300,81 @@ static struct regmap_config regcfg = { .precious_reg = sc16is7xx_regmap_precious, }; +#ifdef CONFIG_SERIAL_SC16IS7XX_SPI +static int sc16is7xx_spi_probe(struct spi_device *spi) +{ + const struct sc16is7xx_devtype *devtype; + unsigned long flags = 0; + struct regmap *regmap; + int ret; + + /* Setup SPI bus */ + spi->bits_per_word = 8; + /* only supports mode 0 on SC16IS762 */ + spi->mode = spi->mode ? : SPI_MODE_0; + spi->max_speed_hz = spi->max_speed_hz ? : 15000000; + ret = spi_setup(spi); + if (ret) + return ret; + + if (spi->dev.of_node) { + const struct of_device_id *of_id = + of_match_device(sc16is7xx_dt_ids, &spi->dev); + + if (!of_id) + return -ENODEV; + + devtype = (struct sc16is7xx_devtype *)of_id->data; + } else { + const struct spi_device_id *id_entry = spi_get_device_id(spi); + + devtype = (struct sc16is7xx_devtype *)id_entry->driver_data; + flags = IRQF_TRIGGER_FALLING; + } + + regcfg.max_register = (0xf << SC16IS7XX_REG_SHIFT) | + (devtype->nr_uart - 1); + regmap = devm_regmap_init_spi(spi, ®cfg); + + return sc16is7xx_probe(&spi->dev, devtype, regmap, spi->irq, flags); +} + +static int sc16is7xx_spi_remove(struct spi_device *spi) +{ + return 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 = of_match_ptr(sc16is7xx_dt_ids), + }, + .probe = sc16is7xx_spi_probe, + .remove = sc16is7xx_spi_remove, + .id_table = sc16is7xx_spi_id_table, +}; + +MODULE_ALIAS("spi:sc16is7xx"); +#endif + +#ifdef CONFIG_SERIAL_SC16IS7XX_I2C static int sc16is7xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct sc16is7xx_devtype *devtype; + const struct sc16is7xx_devtype *devtype; unsigned long flags = 0; struct regmap *regmap; @@ -1215,6 +1382,9 @@ static int sc16is7xx_i2c_probe(struct i2c_client *i2c, const struct of_device_id *of_id = of_match_device(sc16is7xx_dt_ids, &i2c->dev); + if (!of_id) + return -ENODEV; + devtype = (struct sc16is7xx_devtype *)of_id->data; } else { devtype = (struct sc16is7xx_devtype *)id->driver_data; @@ -1235,6 +1405,8 @@ static int sc16is7xx_i2c_remove(struct i2c_client *client) 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, }, @@ -1246,15 +1418,56 @@ MODULE_DEVICE_TABLE(i2c, sc16is7xx_i2c_id_table); static struct i2c_driver sc16is7xx_i2c_uart_driver = { .driver = { .name = SC16IS7XX_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(sc16is7xx_dt_ids), }, .probe = sc16is7xx_i2c_probe, .remove = sc16is7xx_i2c_remove, .id_table = sc16is7xx_i2c_id_table, }; -module_i2c_driver(sc16is7xx_i2c_uart_driver); -MODULE_ALIAS("i2c:sc16is7xx"); + +#endif + +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); + return ret; + } +#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); + return ret; + } +#endif + return ret; +} +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>"); diff --git a/kernel/drivers/tty/serial/serial-tegra.c b/kernel/drivers/tty/serial/serial-tegra.c index 1d5ea3964..1d6fc60ed 100644 --- a/kernel/drivers/tty/serial/serial-tegra.c +++ b/kernel/drivers/tty/serial/serial-tegra.c @@ -131,8 +131,8 @@ struct tegra_uart_port { struct dma_async_tx_descriptor *rx_dma_desc; dma_cookie_t tx_cookie; dma_cookie_t rx_cookie; - int tx_bytes_requested; - int rx_bytes_requested; + unsigned int tx_bytes_requested; + unsigned int rx_bytes_requested; }; static void tegra_uart_start_next_tx(struct tegra_uart_port *tup); @@ -186,7 +186,6 @@ static void set_rts(struct tegra_uart_port *tup, bool active) tegra_uart_write(tup, mcr, UART_MCR); tup->mcr_shadow = mcr; } - return; } static void set_dtr(struct tegra_uart_port *tup, bool active) @@ -202,7 +201,6 @@ static void set_dtr(struct tegra_uart_port *tup, bool active) tegra_uart_write(tup, mcr, UART_MCR); tup->mcr_shadow = mcr; } - return; } static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl) @@ -217,7 +215,6 @@ static void tegra_uart_set_mctrl(struct uart_port *u, unsigned int mctrl) dtr_enable = !!(mctrl & TIOCM_DTR); set_dtr(tup, dtr_enable); - return; } static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl) @@ -234,6 +231,22 @@ static void tegra_uart_break_ctl(struct uart_port *u, int break_ctl) tup->lcr_shadow = lcr; } +/** + * tegra_uart_wait_cycle_time: Wait for N UART clock periods + * + * @tup: Tegra serial port data structure. + * @cycles: Number of clock periods to wait. + * + * Tegra UARTs are clocked at 16X the baud/bit rate and hence the UART + * clock speed is 16X the current baud rate. + */ +static void tegra_uart_wait_cycle_time(struct tegra_uart_port *tup, + unsigned int cycles) +{ + if (tup->current_baud) + udelay(DIV_ROUND_UP(cycles * 1000000, tup->current_baud * 16)); +} + /* Wait for a symbol-time. */ static void tegra_uart_wait_sym_time(struct tegra_uart_port *tup, unsigned int syms) @@ -263,8 +276,12 @@ static void tegra_uart_fifo_reset(struct tegra_uart_port *tup, u8 fcr_bits) /* Dummy read to ensure the write is posted */ tegra_uart_read(tup, UART_SCR); - /* Wait for the flush to propagate. */ - tegra_uart_wait_sym_time(tup, 1); + /* + * For all tegra devices (up to t210), there is a hardware issue that + * requires software to wait for 32 UART clock periods for the flush + * to propagate, otherwise data could be lost. + */ + tegra_uart_wait_cycle_time(tup, 32); } static int tegra_set_baudrate(struct tegra_uart_port *tup, unsigned int baud) @@ -388,9 +405,9 @@ static void tegra_uart_tx_dma_complete(void *args) struct circ_buf *xmit = &tup->uport.state->xmit; struct dma_tx_state state; unsigned long flags; - int count; + unsigned int count; - dmaengine_tx_status(tup->tx_dma_chan, tup->rx_cookie, &state); + dmaengine_tx_status(tup->tx_dma_chan, tup->tx_cookie, &state); count = tup->tx_bytes_requested - state.residue; async_tx_ack(tup->tx_dma_desc); spin_lock_irqsave(&tup->uport.lock, flags); @@ -480,7 +497,7 @@ static void tegra_uart_stop_tx(struct uart_port *u) struct tegra_uart_port *tup = to_tegra_uport(u); struct circ_buf *xmit = &tup->uport.state->xmit; struct dma_tx_state state; - int count; + unsigned int count; if (tup->tx_in_progress != TEGRA_UART_TX_DMA) return; @@ -491,7 +508,6 @@ static void tegra_uart_stop_tx(struct uart_port *u) async_tx_ack(tup->tx_dma_desc); xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); tup->tx_in_progress = 0; - return; } static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup) @@ -503,7 +519,6 @@ static void tegra_uart_handle_tx_pio(struct tegra_uart_port *tup) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&tup->uport); tegra_uart_start_next_tx(tup); - return; } static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, @@ -525,15 +540,18 @@ static void tegra_uart_handle_rx_pio(struct tegra_uart_port *tup, if (!uart_handle_sysrq_char(&tup->uport, ch) && tty) tty_insert_flip_char(tty, ch, flag); } while (1); - - return; } static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, - struct tty_port *tty, int count) + struct tty_port *tty, + unsigned int count) { int copied; + /* If count is zero, then there is no data to be copied */ + if (!count) + return; + tup->uport.icount.rx += count; if (!tty) { dev_err(tup->uport.dev, "No tty port\n"); @@ -551,71 +569,69 @@ static void tegra_uart_copy_rx_to_tty(struct tegra_uart_port *tup, TEGRA_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE); } +static void tegra_uart_rx_buffer_push(struct tegra_uart_port *tup, + unsigned int residue) +{ + struct tty_port *port = &tup->uport.state->port; + struct tty_struct *tty = tty_port_tty_get(port); + unsigned int count; + + async_tx_ack(tup->rx_dma_desc); + count = tup->rx_bytes_requested - residue; + + /* If we are here, DMA is stopped */ + tegra_uart_copy_rx_to_tty(tup, port, count); + + tegra_uart_handle_rx_pio(tup, port); + if (tty) { + tty_flip_buffer_push(port); + tty_kref_put(tty); + } +} + static void tegra_uart_rx_dma_complete(void *args) { struct tegra_uart_port *tup = args; struct uart_port *u = &tup->uport; - int count = tup->rx_bytes_requested; - struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); - struct tty_port *port = &u->state->port; unsigned long flags; + struct dma_tx_state state; + enum dma_status status; - async_tx_ack(tup->rx_dma_desc); spin_lock_irqsave(&u->lock, flags); + status = dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + + if (status == DMA_IN_PROGRESS) { + dev_dbg(tup->uport.dev, "RX DMA is in progress\n"); + goto done; + } + /* Deactivate flow control to stop sender */ if (tup->rts_active) set_rts(tup, false); - /* If we are here, DMA is stopped */ - if (count) - tegra_uart_copy_rx_to_tty(tup, port, count); - - tegra_uart_handle_rx_pio(tup, port); - if (tty) { - spin_unlock_irqrestore(&u->lock, flags); - tty_flip_buffer_push(port); - spin_lock_irqsave(&u->lock, flags); - tty_kref_put(tty); - } + tegra_uart_rx_buffer_push(tup, 0); tegra_uart_start_rx_dma(tup); /* Activate flow control to start transfer */ if (tup->rts_active) set_rts(tup, true); +done: spin_unlock_irqrestore(&u->lock, flags); } -static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup, - unsigned long *flags) +static void tegra_uart_handle_rx_dma(struct tegra_uart_port *tup) { struct dma_tx_state state; - struct tty_struct *tty = tty_port_tty_get(&tup->uport.state->port); - struct tty_port *port = &tup->uport.state->port; - struct uart_port *u = &tup->uport; - int count; /* Deactivate flow control to stop sender */ if (tup->rts_active) set_rts(tup, false); dmaengine_terminate_all(tup->rx_dma_chan); - dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); - async_tx_ack(tup->rx_dma_desc); - count = tup->rx_bytes_requested - state.residue; - - /* If we are here, DMA is stopped */ - if (count) - tegra_uart_copy_rx_to_tty(tup, port, count); - - tegra_uart_handle_rx_pio(tup, port); - if (tty) { - spin_unlock_irqrestore(&u->lock, *flags); - tty_flip_buffer_push(port); - spin_lock_irqsave(&u->lock, *flags); - tty_kref_put(tty); - } + dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + tegra_uart_rx_buffer_push(tup, state.residue); tegra_uart_start_rx_dma(tup); if (tup->rts_active) @@ -663,7 +679,6 @@ static void tegra_uart_handle_modem_signal_change(struct uart_port *u) /* Will start/stop_tx accordingly */ if (msr & UART_MSR_DCTS) uart_handle_cts_change(&tup->uport, msr & UART_MSR_CTS); - return; } static irqreturn_t tegra_uart_isr(int irq, void *data) @@ -680,7 +695,7 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) iir = tegra_uart_read(tup, UART_IIR); if (iir & UART_IIR_NO_INT) { if (is_rx_int) { - tegra_uart_handle_rx_dma(tup, &flags); + tegra_uart_handle_rx_dma(tup); if (tup->rx_in_progress) { ier = tup->ier_shadow; ier |= (UART_IER_RLSI | UART_IER_RTOIE | @@ -735,11 +750,8 @@ static irqreturn_t tegra_uart_isr(int irq, void *data) static void tegra_uart_stop_rx(struct uart_port *u) { struct tegra_uart_port *tup = to_tegra_uport(u); - struct tty_struct *tty; - struct tty_port *port = &u->state->port; struct dma_tx_state state; unsigned long ier; - int count; if (tup->rts_active) set_rts(tup, false); @@ -747,8 +759,6 @@ static void tegra_uart_stop_rx(struct uart_port *u) if (!tup->rx_in_progress) return; - tty = tty_port_tty_get(&tup->uport.state->port); - tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */ ier = tup->ier_shadow; @@ -757,21 +767,9 @@ static void tegra_uart_stop_rx(struct uart_port *u) tup->ier_shadow = ier; tegra_uart_write(tup, ier, UART_IER); tup->rx_in_progress = 0; - if (tup->rx_dma_chan) { - dmaengine_terminate_all(tup->rx_dma_chan); - dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); - async_tx_ack(tup->rx_dma_desc); - count = tup->rx_bytes_requested - state.residue; - tegra_uart_copy_rx_to_tty(tup, port, count); - tegra_uart_handle_rx_pio(tup, port); - } else { - tegra_uart_handle_rx_pio(tup, port); - } - if (tty) { - tty_flip_buffer_push(port); - tty_kref_put(tty); - } - return; + dmaengine_terminate_all(tup->rx_dma_chan); + dmaengine_tx_status(tup->rx_dma_chan, tup->rx_cookie, &state); + tegra_uart_rx_buffer_push(tup, state.residue); } static void tegra_uart_hw_deinit(struct tegra_uart_port *tup) @@ -865,6 +863,16 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) tup->fcr_shadow |= TEGRA_UART_TX_TRIG_16B; tegra_uart_write(tup, tup->fcr_shadow, UART_FCR); + /* Dummy read to ensure the write is posted */ + tegra_uart_read(tup, UART_SCR); + + /* + * For all tegra devices (up to t210), there is a hardware issue that + * requires software to wait for 3 UART clock periods after enabling + * the TX fifo, otherwise data could be lost. + */ + tegra_uart_wait_cycle_time(tup, 3); + /* * Initialize the UART with default configuration * (115200, N, 8, 1) so that the receive DMA buffer may be @@ -905,6 +913,28 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) return 0; } +static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup, + bool dma_to_memory) +{ + if (dma_to_memory) { + dmaengine_terminate_all(tup->rx_dma_chan); + dma_release_channel(tup->rx_dma_chan); + dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE, + tup->rx_dma_buf_virt, tup->rx_dma_buf_phys); + tup->rx_dma_chan = NULL; + tup->rx_dma_buf_phys = 0; + tup->rx_dma_buf_virt = NULL; + } else { + dmaengine_terminate_all(tup->tx_dma_chan); + dma_release_channel(tup->tx_dma_chan); + dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys, + UART_XMIT_SIZE, DMA_TO_DEVICE); + tup->tx_dma_chan = NULL; + tup->tx_dma_buf_phys = 0; + tup->tx_dma_buf_virt = NULL; + } +} + static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, bool dma_to_memory) { @@ -933,67 +963,39 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, dma_release_channel(dma_chan); return -ENOMEM; } + dma_sconfig.src_addr = tup->uport.mapbase; + dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + dma_sconfig.src_maxburst = 4; + tup->rx_dma_chan = dma_chan; + tup->rx_dma_buf_virt = dma_buf; + tup->rx_dma_buf_phys = dma_phys; } else { dma_phys = dma_map_single(tup->uport.dev, tup->uport.state->xmit.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; - } - - if (dma_to_memory) { - dma_sconfig.src_addr = tup->uport.mapbase; - dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; - dma_sconfig.src_maxburst = 4; - } else { dma_sconfig.dst_addr = tup->uport.mapbase; dma_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_sconfig.dst_maxburst = 16; + tup->tx_dma_chan = dma_chan; + tup->tx_dma_buf_virt = dma_buf; + tup->tx_dma_buf_phys = dma_phys; } ret = dmaengine_slave_config(dma_chan, &dma_sconfig); if (ret < 0) { dev_err(tup->uport.dev, "Dma slave config failed, err = %d\n", ret); - goto scrub; + tegra_uart_dma_channel_free(tup, dma_to_memory); + return ret; } - if (dma_to_memory) { - tup->rx_dma_chan = dma_chan; - tup->rx_dma_buf_virt = dma_buf; - tup->rx_dma_buf_phys = dma_phys; - } else { - tup->tx_dma_chan = dma_chan; - tup->tx_dma_buf_virt = dma_buf; - tup->tx_dma_buf_phys = dma_phys; - } return 0; - -scrub: - dma_release_channel(dma_chan); - return ret; -} - -static void tegra_uart_dma_channel_free(struct tegra_uart_port *tup, - bool dma_to_memory) -{ - struct dma_chan *dma_chan; - - if (dma_to_memory) { - dma_free_coherent(tup->uport.dev, TEGRA_UART_RX_DMA_BUFFER_SIZE, - tup->rx_dma_buf_virt, tup->rx_dma_buf_phys); - dma_chan = tup->rx_dma_chan; - tup->rx_dma_chan = NULL; - tup->rx_dma_buf_phys = 0; - tup->rx_dma_buf_virt = NULL; - } else { - dma_unmap_single(tup->uport.dev, tup->tx_dma_buf_phys, - UART_XMIT_SIZE, DMA_TO_DEVICE); - dma_chan = tup->tx_dma_chan; - tup->tx_dma_chan = NULL; - tup->tx_dma_buf_phys = 0; - tup->tx_dma_buf_virt = NULL; - } - dma_release_channel(dma_chan); } static int tegra_uart_startup(struct uart_port *u) @@ -1045,7 +1047,6 @@ static void tegra_uart_flush_buffer(struct uart_port *u) tup->tx_bytes = 0; if (tup->tx_dma_chan) dmaengine_terminate_all(tup->tx_dma_chan); - return; } static void tegra_uart_shutdown(struct uart_port *u) @@ -1060,8 +1061,6 @@ static void tegra_uart_shutdown(struct uart_port *u) tegra_uart_dma_channel_free(tup, true); tegra_uart_dma_channel_free(tup, false); free_irq(u->irq, tup); - - tegra_uart_flush_buffer(u); } static void tegra_uart_enable_ms(struct uart_port *u) @@ -1187,7 +1186,6 @@ static void tegra_uart_set_termios(struct uart_port *u, tegra_uart_read(tup, UART_IER); spin_unlock_irqrestore(&u->lock, flags); - return; } static const char *tegra_uart_type(struct uart_port *u) diff --git a/kernel/drivers/tty/serial/serial_core.c b/kernel/drivers/tty/serial/serial_core.c index ec540445b..def5199ca 100644 --- a/kernel/drivers/tty/serial/serial_core.c +++ b/kernel/drivers/tty/serial/serial_core.c @@ -335,18 +335,29 @@ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old, unsigned int min, unsigned int max) { - unsigned int try, baud, altbaud = 38400; + unsigned int try; + unsigned int baud; + unsigned int altbaud; int hung_up = 0; upf_t flags = port->flags & UPF_SPD_MASK; - if (flags == UPF_SPD_HI) + switch (flags) { + case UPF_SPD_HI: altbaud = 57600; - else if (flags == UPF_SPD_VHI) + break; + case UPF_SPD_VHI: altbaud = 115200; - else if (flags == UPF_SPD_SHI) + break; + case UPF_SPD_SHI: altbaud = 230400; - else if (flags == UPF_SPD_WARP) + break; + case UPF_SPD_WARP: altbaud = 460800; + break; + default: + altbaud = 38400; + break; + } for (try = 0; try < 2; try++) { baud = tty_termios_baud_rate(termios); @@ -894,12 +905,10 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, * need to rate-limit; it's CAP_SYS_ADMIN only. */ if (uport->flags & UPF_SPD_MASK) { - char buf[64]; - dev_notice(uport->dev, "%s sets custom speed on %s. This is deprecated.\n", current->comm, - tty_name(port->tty, buf)); + tty_name(port->tty)); } uart_change_speed(tty, state, NULL); } @@ -1368,7 +1377,6 @@ static void uart_close(struct tty_struct *tty, struct file *filp) struct uart_state *state = tty->driver_data; struct tty_port *port; struct uart_port *uport; - unsigned long flags; if (!state) { struct uart_driver *drv = tty->driver->driver_state; @@ -1394,10 +1402,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp) * disable the receive line status interrupts. */ if (port->flags & ASYNC_INITIALIZED) { - unsigned long flags; - spin_lock_irqsave(&uport->lock, flags); + spin_lock_irq(&uport->lock); uport->ops->stop_rx(uport); - spin_unlock_irqrestore(&uport->lock, flags); + spin_unlock_irq(&uport->lock); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially @@ -1410,17 +1417,17 @@ static void uart_close(struct tty_struct *tty, struct file *filp) uart_shutdown(tty, state); tty_port_tty_set(port, NULL); - spin_lock_irqsave(&port->lock, flags); + spin_lock_irq(&port->lock); if (port->blocked_open) { - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irq(&port->lock); if (port->close_delay) msleep_interruptible(jiffies_to_msecs(port->close_delay)); - spin_lock_irqsave(&port->lock, flags); + spin_lock_irq(&port->lock); } else if (!uart_console(uport)) { - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irq(&port->lock); uart_change_pm(state, UART_PM_STATE_OFF); - spin_lock_irqsave(&port->lock, flags); + spin_lock_irq(&port->lock); } /* @@ -1428,9 +1435,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) */ clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); clear_bit(ASYNCB_CLOSING, &port->flags); - spin_unlock_irqrestore(&port->lock, flags); + spin_unlock_irq(&port->lock); wake_up_interruptible(&port->open_wait); - wake_up_interruptible(&port->close_wait); mutex_unlock(&port->mutex); @@ -1523,11 +1529,6 @@ static void uart_hangup(struct tty_struct *tty) mutex_unlock(&port->mutex); } -static int uart_port_activate(struct tty_port *port, struct tty_struct *tty) -{ - return 0; -} - static void uart_port_shutdown(struct tty_port *port) { struct uart_state *state = container_of(port, struct uart_state, port); @@ -1817,8 +1818,8 @@ uart_get_console(struct uart_port *ports, int nr, struct console *co) * @options: ptr for <options> field; NULL if not present (out) * * Decodes earlycon kernel command line parameters of the form - * earlycon=<name>,io|mmio|mmio32,<addr>,<options> - * console=<name>,io|mmio|mmio32,<addr>,<options> + * earlycon=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options> + * console=<name>,io|mmio|mmio32|mmio32be|mmio32native,<addr>,<options> * * The optional form * earlycon=<name>,0x<addr>,<options> @@ -1836,6 +1837,13 @@ int uart_parse_earlycon(char *p, unsigned char *iotype, unsigned long *addr, } else if (strncmp(p, "mmio32,", 7) == 0) { *iotype = UPIO_MEM32; p += 7; + } else if (strncmp(p, "mmio32be,", 9) == 0) { + *iotype = UPIO_MEM32BE; + p += 9; + } else if (strncmp(p, "mmio32native,", 13) == 0) { + *iotype = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ? + UPIO_MEM32BE : UPIO_MEM32; + p += 13; } else if (strncmp(p, "io,", 3) == 0) { *iotype = UPIO_PORT; p += 3; @@ -2367,8 +2375,6 @@ static const struct tty_operations uart_ops = { }; static const struct tty_port_operations uart_port_ops = { - .activate = uart_port_activate, - .shutdown = uart_port_shutdown, .carrier_raised = uart_carrier_raised, .dtr_rts = uart_dtr_rts, }; diff --git a/kernel/drivers/tty/serial/serial_ks8695.c b/kernel/drivers/tty/serial/serial_ks8695.c index 5c79bdab9..b4decf878 100644 --- a/kernel/drivers/tty/serial/serial_ks8695.c +++ b/kernel/drivers/tty/serial/serial_ks8695.c @@ -328,7 +328,7 @@ static int ks8695uart_startup(struct uart_port *port) { int retval; - set_irq_flags(KS8695_IRQ_UART_TX, IRQF_VALID | IRQF_NOAUTOEN); + irq_modify_status(KS8695_IRQ_UART_TX, IRQ_NOREQUEST, IRQ_NOAUTOEN); tx_enable(port, 0); rx_enable(port, 1); ms_enable(port, 1); diff --git a/kernel/drivers/tty/serial/serial_mctrl_gpio.c b/kernel/drivers/tty/serial/serial_mctrl_gpio.c index 0ec756c62..3eb57eb53 100644 --- a/kernel/drivers/tty/serial/serial_mctrl_gpio.c +++ b/kernel/drivers/tty/serial/serial_mctrl_gpio.c @@ -12,18 +12,23 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * */ #include <linux/err.h> #include <linux/device.h> +#include <linux/irq.h> #include <linux/gpio/consumer.h> #include <linux/termios.h> +#include <linux/serial_core.h> #include "serial_mctrl_gpio.h" struct mctrl_gpios { + struct uart_port *port; struct gpio_desc *gpio[UART_GPIO_MAX]; + int irq[UART_GPIO_MAX]; + unsigned int mctrl_prev; + bool mctrl_on; }; static const struct { @@ -49,13 +54,12 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) unsigned int count = 0; for (i = 0; i < UART_GPIO_MAX; i++) - if (!IS_ERR_OR_NULL(gpios->gpio[i]) && - mctrl_gpios_desc[i].dir_out) { + if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { desc_array[count] = gpios->gpio[i]; value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl); count++; } - gpiod_set_array(count, desc_array, value_array); + gpiod_set_array_value(count, desc_array, value_array); } EXPORT_SYMBOL_GPL(mctrl_gpio_set); @@ -83,7 +87,7 @@ unsigned int mctrl_gpio_get(struct mctrl_gpios *gpios, unsigned int *mctrl) } EXPORT_SYMBOL_GPL(mctrl_gpio_get); -struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx) +struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx) { struct mctrl_gpios *gpios; enum mctrl_gpio_idx i; @@ -111,15 +115,135 @@ struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx) return gpios; } -EXPORT_SYMBOL_GPL(mctrl_gpio_init); +EXPORT_SYMBOL_GPL(mctrl_gpio_init_noauto); + +#define MCTRL_ANY_DELTA (TIOCM_RI | TIOCM_DSR | TIOCM_CD | TIOCM_CTS) +static irqreturn_t mctrl_gpio_irq_handle(int irq, void *context) +{ + struct mctrl_gpios *gpios = context; + struct uart_port *port = gpios->port; + u32 mctrl = gpios->mctrl_prev; + u32 mctrl_diff; + + mctrl_gpio_get(gpios, &mctrl); + + mctrl_diff = mctrl ^ gpios->mctrl_prev; + gpios->mctrl_prev = mctrl; + + if (mctrl_diff & MCTRL_ANY_DELTA && port->state != NULL) { + if ((mctrl_diff & mctrl) & TIOCM_RI) + port->icount.rng++; + + if ((mctrl_diff & mctrl) & TIOCM_DSR) + port->icount.dsr++; + + if (mctrl_diff & TIOCM_CD) + uart_handle_dcd_change(port, mctrl & TIOCM_CD); + + if (mctrl_diff & TIOCM_CTS) + uart_handle_cts_change(port, mctrl & TIOCM_CTS); + + wake_up_interruptible(&port->state->port.delta_msr_wait); + } + + return IRQ_HANDLED; +} + +struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx) +{ + struct mctrl_gpios *gpios; + enum mctrl_gpio_idx i; + + gpios = mctrl_gpio_init_noauto(port->dev, idx); + if (IS_ERR(gpios)) + return gpios; + + gpios->port = port; + + for (i = 0; i < UART_GPIO_MAX; ++i) { + int ret; + + if (!gpios->gpio[i] || mctrl_gpios_desc[i].dir_out) + continue; + + ret = gpiod_to_irq(gpios->gpio[i]); + if (ret <= 0) { + dev_err(port->dev, + "failed to find corresponding irq for %s (idx=%d, err=%d)\n", + mctrl_gpios_desc[i].name, idx, ret); + return ERR_PTR(ret); + } + gpios->irq[i] = ret; + + /* irqs should only be enabled in .enable_ms */ + irq_set_status_flags(gpios->irq[i], IRQ_NOAUTOEN); + + ret = devm_request_irq(port->dev, gpios->irq[i], + mctrl_gpio_irq_handle, + IRQ_TYPE_EDGE_BOTH, dev_name(port->dev), + gpios); + if (ret) { + /* alternatively implement polling */ + dev_err(port->dev, + "failed to request irq for %s (idx=%d, err=%d)\n", + mctrl_gpios_desc[i].name, idx, ret); + return ERR_PTR(ret); + } + } + + return gpios; +} void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios) { enum mctrl_gpio_idx i; - for (i = 0; i < UART_GPIO_MAX; i++) - if (!IS_ERR_OR_NULL(gpios->gpio[i])) + 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); + +void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios) +{ + enum mctrl_gpio_idx i; + + /* .enable_ms may be called multiple times */ + if (gpios->mctrl_on) + return; + + gpios->mctrl_on = true; + + /* get initial status of modem lines GPIOs */ + mctrl_gpio_get(gpios, &gpios->mctrl_prev); + + for (i = 0; i < UART_GPIO_MAX; ++i) { + if (!gpios->irq[i]) + continue; + + enable_irq(gpios->irq[i]); + } +} +EXPORT_SYMBOL_GPL(mctrl_gpio_enable_ms); + +void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) +{ + enum mctrl_gpio_idx i; + + if (!gpios->mctrl_on) + return; + + gpios->mctrl_on = false; + + for (i = 0; i < UART_GPIO_MAX; ++i) { + if (!gpios->irq[i]) + continue; + + disable_irq(gpios->irq[i]); + } +} diff --git a/kernel/drivers/tty/serial/serial_mctrl_gpio.h b/kernel/drivers/tty/serial/serial_mctrl_gpio.h index 400ba0494..9716db283 100644 --- a/kernel/drivers/tty/serial/serial_mctrl_gpio.h +++ b/kernel/drivers/tty/serial/serial_mctrl_gpio.h @@ -22,6 +22,8 @@ #include <linux/device.h> #include <linux/gpio/consumer.h> +struct uart_port; + enum mctrl_gpio_idx { UART_GPIO_CTS, UART_GPIO_DSR, @@ -60,12 +62,22 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, enum mctrl_gpio_idx gidx); /* + * Request and set direction of modem control lines GPIOs and sets up irq + * handling. + * devm_* functions are used, so there's no need to call mctrl_gpio_free(). + * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on + * allocation error. + */ +struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx); + +/* * Request and set direction of modem control lines GPIOs. * devm_* functions are used, so there's no need to call mctrl_gpio_free(). * Returns a pointer to the allocated mctrl structure if ok, -ENOMEM on * allocation error. */ -struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx); +struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, + unsigned int idx); /* * Free the mctrl_gpios structure. @@ -74,6 +86,16 @@ struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx); */ void mctrl_gpio_free(struct device *dev, struct mctrl_gpios *gpios); +/* + * Enable gpio interrupts to report status line changes. + */ +void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios); + +/* + * Disable gpio interrupts to report status line changes. + */ +void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios); + #else /* GPIOLIB */ static inline @@ -95,7 +117,13 @@ struct gpio_desc *mctrl_gpio_to_gpiod(struct mctrl_gpios *gpios, } static inline -struct mctrl_gpios *mctrl_gpio_init(struct device *dev, unsigned int idx) +struct mctrl_gpios *mctrl_gpio_init(struct uart_port *port, unsigned int idx) +{ + return ERR_PTR(-ENOSYS); +} + +static inline +struct mctrl_gpios *mctrl_gpio_init_noauto(struct device *dev, unsigned int idx) { return ERR_PTR(-ENOSYS); } @@ -105,6 +133,14 @@ 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_disable_ms(struct mctrl_gpios *gpios) +{ +} + #endif /* GPIOLIB */ #endif diff --git a/kernel/drivers/tty/serial/sh-sci.c b/kernel/drivers/tty/serial/sh-sci.c index e7d6566fa..51c7507b0 100644 --- a/kernel/drivers/tty/serial/sh-sci.c +++ b/kernel/drivers/tty/serial/sh-sci.c @@ -81,10 +81,12 @@ struct sci_port { /* Platform configuration */ struct plat_sci_port *cfg; - int overrun_bit; + unsigned int overrun_reg; + unsigned int overrun_mask; unsigned int error_mask; + unsigned int error_clear; unsigned int sampling_rate; - + resource_size_t reg_size; /* Break timer */ struct timer_list break_timer; @@ -102,19 +104,15 @@ struct sci_port { struct dma_chan *chan_rx; #ifdef CONFIG_SERIAL_SH_SCI_DMA - struct dma_async_tx_descriptor *desc_tx; - struct dma_async_tx_descriptor *desc_rx[2]; dma_cookie_t cookie_tx; dma_cookie_t cookie_rx[2]; dma_cookie_t active_rx; - struct scatterlist sg_tx; - unsigned int sg_len_tx; + dma_addr_t tx_dma_addr; + unsigned int tx_dma_len; struct scatterlist sg_rx[2]; + void *rx_buf[2]; size_t buf_len_rx; - struct sh_dmae_slave param_tx; - struct sh_dmae_slave param_rx; struct work_struct work_tx; - struct work_struct work_rx; struct timer_list rx_timer; unsigned int rx_timeout; #endif @@ -122,11 +120,6 @@ struct sci_port { struct notifier_block freq_transition; }; -/* Function prototypes */ -static void sci_start_tx(struct uart_port *port); -static void sci_stop_tx(struct uart_port *port); -static void sci_start_rx(struct uart_port *port); - #define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS static struct sci_port sci_ports[SCI_NPORTS]; @@ -145,7 +138,7 @@ struct plat_sci_reg { /* Helper for invalidating specific entries of an inherited map. */ #define sci_reg_invalid { .offset = 0, .size = 0 } -static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { +static const struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCIx_PROBE_REGTYPE] = { [0 ... SCIx_NR_REGS - 1] = sci_reg_invalid, }, @@ -168,6 +161,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -188,6 +183,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -207,6 +204,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = { 0x30, 16 }, + [SCPDR] = { 0x34, 16 }, }, /* @@ -226,6 +225,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = { 0x30, 16 }, + [SCPDR] = { 0x34, 16 }, }, /* @@ -246,6 +247,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -265,6 +268,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -284,6 +289,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -303,6 +310,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = { 0x20, 16 }, [SCLSR] = { 0x24, 16 }, [HSSRR] = { 0x40, 16 }, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -323,6 +332,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = { 0x24, 16 }, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -343,6 +354,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = { 0x24, 16 }, [SCLSR] = { 0x28, 16 }, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, /* @@ -363,6 +376,8 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { [SCSPTR] = sci_reg_invalid, [SCLSR] = sci_reg_invalid, [HSSRR] = sci_reg_invalid, + [SCPCR] = sci_reg_invalid, + [SCPDR] = sci_reg_invalid, }, }; @@ -376,7 +391,7 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { */ static unsigned int sci_serial_in(struct uart_port *p, int offset) { - struct plat_sci_reg *reg = sci_getreg(p, offset); + const struct plat_sci_reg *reg = sci_getreg(p, offset); if (reg->size == 8) return ioread8(p->membase + (reg->offset << p->regshift)); @@ -390,7 +405,7 @@ static unsigned int sci_serial_in(struct uart_port *p, int offset) static void sci_serial_out(struct uart_port *p, int offset, int value) { - struct plat_sci_reg *reg = sci_getreg(p, offset); + const struct plat_sci_reg *reg = sci_getreg(p, offset); if (reg->size == 8) iowrite8(value, p->membase + (reg->offset << p->regshift)); @@ -466,6 +481,105 @@ static void sci_port_disable(struct sci_port *sci_port) pm_runtime_put_sync(sci_port->port.dev); } +static inline unsigned long port_rx_irq_mask(struct uart_port *port) +{ + /* + * Not all ports (such as SCIFA) will support REIE. Rather than + * special-casing the port type, we check the port initialization + * IRQ enable mask to see whether the IRQ is desired at all. If + * it's unset, it's logically inferred that there's no point in + * testing for it. + */ + return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE); +} + +static void sci_start_tx(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + unsigned short ctrl; + +#ifdef CONFIG_SERIAL_SH_SCI_DMA + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 new, scr = serial_port_in(port, SCSCR); + if (s->chan_tx) + new = scr | SCSCR_TDRQE; + else + new = scr & ~SCSCR_TDRQE; + if (new != scr) + serial_port_out(port, SCSCR, new); + } + + if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && + dma_submit_error(s->cookie_tx)) { + s->cookie_tx = 0; + schedule_work(&s->work_tx); + } +#endif + + if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ + ctrl = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, ctrl | SCSCR_TIE); + } +} + +static void sci_stop_tx(struct uart_port *port) +{ + unsigned short ctrl; + + /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ + ctrl = serial_port_in(port, SCSCR); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~SCSCR_TDRQE; + + ctrl &= ~SCSCR_TIE; + + serial_port_out(port, SCSCR, ctrl); +} + +static void sci_start_rx(struct uart_port *port) +{ + unsigned short ctrl; + + ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~SCSCR_RDRQE; + + serial_port_out(port, SCSCR, ctrl); +} + +static void sci_stop_rx(struct uart_port *port) +{ + unsigned short ctrl; + + ctrl = serial_port_in(port, SCSCR); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + ctrl &= ~SCSCR_RDRQE; + + ctrl &= ~port_rx_irq_mask(port); + + serial_port_out(port, SCSCR, ctrl); +} + +static void sci_clear_SCxSR(struct uart_port *port, unsigned int mask) +{ + if (port->type == PORT_SCI) { + /* Just store the mask */ + serial_port_out(port, SCxSR, mask); + } else if (to_sci_port(port)->overrun_mask == SCIFA_ORER) { + /* SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 */ + /* Only clear the status bits we want to clear */ + serial_port_out(port, SCxSR, + serial_port_in(port, SCxSR) & mask); + } else { + /* Store the mask, clear parity/framing errors */ + serial_port_out(port, SCxSR, mask & ~(SCIF_FERC | SCIF_PERC)); + } +} + #if defined(CONFIG_CONSOLE_POLL) || defined(CONFIG_SERIAL_SH_SCI_CONSOLE) #ifdef CONFIG_CONSOLE_POLL @@ -477,7 +591,7 @@ static int sci_poll_get_char(struct uart_port *port) do { status = serial_port_in(port, SCxSR); if (status & SCxSR_ERRORS(port)) { - serial_port_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); continue; } break; @@ -490,7 +604,7 @@ static int sci_poll_get_char(struct uart_port *port) /* Dummy read */ serial_port_in(port, SCxSR); - serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); return c; } @@ -505,14 +619,14 @@ static void sci_poll_put_char(struct uart_port *port, unsigned char c) } while (!(status & SCxSR_TDxE(port))); serial_port_out(port, SCxTDR, c); - serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); + sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port) & ~SCxSR_TEND(port)); } #endif /* CONFIG_CONSOLE_POLL || CONFIG_SERIAL_SH_SCI_CONSOLE */ static void sci_init_pins(struct uart_port *port, unsigned int cflag) { struct sci_port *s = to_sci_port(port); - struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; + const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; /* * Use port-specific handler if provided. @@ -542,7 +656,7 @@ static void sci_init_pins(struct uart_port *port, unsigned int cflag) static int sci_txfill(struct uart_port *port) { - struct plat_sci_reg *reg; + const struct plat_sci_reg *reg; reg = sci_getreg(port, SCTFDR); if (reg->size) @@ -562,7 +676,7 @@ static int sci_txroom(struct uart_port *port) static int sci_rxfill(struct uart_port *port) { - struct plat_sci_reg *reg; + const struct plat_sci_reg *reg; reg = sci_getreg(port, SCRFDR); if (reg->size) @@ -632,7 +746,7 @@ static void sci_transmit_chars(struct uart_port *port) port->icount.tx++; } while (--count > 0); - serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port)); if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); @@ -643,7 +757,7 @@ static void sci_transmit_chars(struct uart_port *port) if (port->type != PORT_SCI) { serial_port_in(port, SCxSR); /* Dummy read */ - serial_port_out(port, SCxSR, SCxSR_TDxE_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port)); } ctrl |= SCSCR_TIE; @@ -727,7 +841,7 @@ static void sci_receive_chars(struct uart_port *port) } serial_port_in(port, SCxSR); /* dummy read */ - serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); copied += count; port->icount.rx += count; @@ -738,7 +852,7 @@ static void sci_receive_chars(struct uart_port *port) tty_flip_buffer_push(tport); } else { serial_port_in(port, SCxSR); /* dummy read */ - serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); } } @@ -781,7 +895,7 @@ static int sci_handle_errors(struct uart_port *port) struct sci_port *s = to_sci_port(port); /* Handle overruns */ - if (status & (1 << s->overrun_bit)) { + if (status & s->overrun_mask) { port->icount.overrun++; /* overrun error */ @@ -843,33 +957,18 @@ static int sci_handle_fifo_overrun(struct uart_port *port) { struct tty_port *tport = &port->state->port; struct sci_port *s = to_sci_port(port); - struct plat_sci_reg *reg; - int copied = 0, offset; - u16 status, bit; - - switch (port->type) { - case PORT_SCIF: - case PORT_HSCIF: - offset = SCLSR; - break; - case PORT_SCIFA: - case PORT_SCIFB: - offset = SCxSR; - break; - default: - return 0; - } + const struct plat_sci_reg *reg; + int copied = 0; + u16 status; - reg = sci_getreg(port, offset); + reg = sci_getreg(port, s->overrun_reg); if (!reg->size) return 0; - status = serial_port_in(port, offset); - bit = 1 << s->overrun_bit; - - if (status & bit) { - status &= ~bit; - serial_port_out(port, offset, status); + status = serial_port_in(port, s->overrun_reg); + if (status & s->overrun_mask) { + status &= ~s->overrun_mask; + serial_port_out(port, s->overrun_reg, status); port->icount.overrun++; @@ -916,6 +1015,460 @@ static int sci_handle_breaks(struct uart_port *port) return copied; } +#ifdef CONFIG_SERIAL_SH_SCI_DMA +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; + unsigned long flags; + + dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); + + spin_lock_irqsave(&port->lock, flags); + + xmit->tail += s->tx_dma_len; + xmit->tail &= UART_XMIT_SIZE - 1; + + port->icount.tx += s->tx_dma_len; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (!uart_circ_empty(xmit)) { + s->cookie_tx = 0; + schedule_work(&s->work_tx); + } else { + s->cookie_tx = -EINVAL; + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + u16 ctrl = serial_port_in(port, SCSCR); + serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE); + } + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +/* Locking: called with port lock held */ +static int sci_dma_rx_push(struct sci_port *s, void *buf, size_t count) +{ + struct uart_port *port = &s->port; + struct tty_port *tport = &port->state->port; + int copied; + + copied = tty_insert_flip_string(tport, buf, count); + if (copied < count) { + dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n", + count - copied); + port->icount.buf_overrun++; + } + + port->icount.rx += copied; + + return copied; +} + +static int sci_dma_rx_find_active(struct sci_port *s) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(s->cookie_rx); i++) + if (s->active_rx == s->cookie_rx[i]) + return i; + + dev_err(s->port.dev, "%s: Rx cookie %d not found!\n", __func__, + s->active_rx); + return -1; +} + +static void sci_rx_dma_release(struct sci_port *s, bool enable_pio) +{ + struct dma_chan *chan = s->chan_rx; + struct uart_port *port = &s->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + s->chan_rx = NULL; + s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; + spin_unlock_irqrestore(&port->lock, flags); + dmaengine_terminate_all(chan); + dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0], + sg_dma_address(&s->sg_rx[0])); + dma_release_channel(chan); + if (enable_pio) + sci_start_rx(port); +} + +static void sci_dma_rx_complete(void *arg) +{ + struct sci_port *s = arg; + struct dma_chan *chan = s->chan_rx; + struct uart_port *port = &s->port; + struct dma_async_tx_descriptor *desc; + unsigned long flags; + int active, count = 0; + + dev_dbg(port->dev, "%s(%d) active cookie %d\n", __func__, port->line, + s->active_rx); + + spin_lock_irqsave(&port->lock, 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); + + mod_timer(&s->rx_timer, jiffies + s->rx_timeout); + + if (count) + tty_flip_buffer_push(&port->state->port); + + desc = dmaengine_prep_slave_sg(s->chan_rx, &s->sg_rx[active], 1, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + goto fail; + + desc->callback = sci_dma_rx_complete; + desc->callback_param = s; + s->cookie_rx[active] = dmaengine_submit(desc); + if (dma_submit_error(s->cookie_rx[active])) + goto fail; + + s->active_rx = s->cookie_rx[!active]; + + dma_async_issue_pending(chan); + + dev_dbg(port->dev, "%s: cookie %d #%d, new active cookie %d\n", + __func__, s->cookie_rx[active], active, s->active_rx); + spin_unlock_irqrestore(&port->lock, flags); + return; + +fail: + spin_unlock_irqrestore(&port->lock, flags); + dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); + sci_rx_dma_release(s, true); +} + +static void sci_tx_dma_release(struct sci_port *s, bool enable_pio) +{ + struct dma_chan *chan = s->chan_tx; + struct uart_port *port = &s->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + s->chan_tx = NULL; + s->cookie_tx = -EINVAL; + spin_unlock_irqrestore(&port->lock, flags); + dmaengine_terminate_all(chan); + dma_unmap_single(chan->device->dev, s->tx_dma_addr, UART_XMIT_SIZE, + DMA_TO_DEVICE); + dma_release_channel(chan); + if (enable_pio) + sci_start_tx(port); +} + +static void sci_submit_rx(struct sci_port *s) +{ + struct dma_chan *chan = s->chan_rx; + int i; + + for (i = 0; i < 2; i++) { + struct scatterlist *sg = &s->sg_rx[i]; + struct dma_async_tx_descriptor *desc; + + desc = dmaengine_prep_slave_sg(chan, + sg, 1, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) + goto fail; + + desc->callback = sci_dma_rx_complete; + desc->callback_param = s; + s->cookie_rx[i] = dmaengine_submit(desc); + if (dma_submit_error(s->cookie_rx[i])) + goto fail; + + dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", __func__, + s->cookie_rx[i], i); + } + + s->active_rx = s->cookie_rx[0]; + + dma_async_issue_pending(chan); + return; + +fail: + if (i) + dmaengine_terminate_all(chan); + for (i = 0; i < 2; i++) + s->cookie_rx[i] = -EINVAL; + s->active_rx = -EINVAL; + dev_warn(s->port.dev, "Failed to re-start Rx DMA, using PIO\n"); + sci_rx_dma_release(s, true); +} + +static void work_fn_tx(struct work_struct *work) +{ + struct sci_port *s = container_of(work, struct sci_port, work_tx); + 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; + dma_addr_t buf; + + /* + * DMA is idle now. + * Port xmit buffer is already mapped, and it is one page... Just adjust + * offsets and lengths. Since it is a circular buffer, we have to + * transmit till the end, and then the rest. Take the port lock to get a + * consistent xmit buffer state. + */ + spin_lock_irq(&port->lock); + buf = s->tx_dma_addr + (xmit->tail & (UART_XMIT_SIZE - 1)); + s->tx_dma_len = min_t(unsigned int, + CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE), + CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE)); + spin_unlock_irq(&port->lock); + + desc = dmaengine_prep_slave_single(chan, buf, s->tx_dma_len, + DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_warn(port->dev, "Failed preparing Tx DMA descriptor\n"); + /* switch to PIO */ + sci_tx_dma_release(s, true); + return; + } + + dma_sync_single_for_device(chan->device->dev, buf, s->tx_dma_len, + DMA_TO_DEVICE); + + spin_lock_irq(&port->lock); + desc->callback = sci_dma_tx_complete; + desc->callback_param = s; + spin_unlock_irq(&port->lock); + s->cookie_tx = dmaengine_submit(desc); + if (dma_submit_error(s->cookie_tx)) { + dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); + /* switch to PIO */ + sci_tx_dma_release(s, true); + return; + } + + dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", + __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx); + + dma_async_issue_pending(chan); +} + +static void rx_timer_fn(unsigned long arg) +{ + struct sci_port *s = (struct sci_port *)arg; + struct dma_chan *chan = s->chan_rx; + struct uart_port *port = &s->port; + struct dma_tx_state state; + enum dma_status status; + unsigned long flags; + unsigned int read; + int active, count; + u16 scr; + + spin_lock_irqsave(&port->lock, flags); + + dev_dbg(port->dev, "DMA Rx timed out\n"); + + active = sci_dma_rx_find_active(s); + if (active < 0) { + spin_unlock_irqrestore(&port->lock, flags); + return; + } + + status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); + if (status == DMA_COMPLETE) { + dev_dbg(port->dev, "Cookie %d #%d has already completed\n", + s->active_rx, active); + spin_unlock_irqrestore(&port->lock, flags); + + /* Let packet complete handler take care of the packet */ + return; + } + + dmaengine_pause(chan); + + /* + * sometimes DMA transfer doesn't stop even if it is stopped and + * data keeps on coming until transaction is complete so check + * for DMA_COMPLETE again + * Let packet complete handler take care of the packet + */ + status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); + if (status == DMA_COMPLETE) { + spin_unlock_irqrestore(&port->lock, flags); + dev_dbg(port->dev, "Transaction complete after DMA engine was stopped"); + return; + } + + /* Handle incomplete DMA receive */ + dmaengine_terminate_all(s->chan_rx); + read = sg_dma_len(&s->sg_rx[active]) - state.residue; + dev_dbg(port->dev, "Read %u bytes with cookie %d\n", read, + s->active_rx); + + if (read) { + count = sci_dma_rx_push(s, s->rx_buf[active], read); + if (count) + tty_flip_buffer_push(&port->state->port); + } + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + sci_submit_rx(s); + + /* Direct new serial port interrupts back to CPU */ + scr = serial_port_in(port, SCSCR); + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + scr &= ~SCSCR_RDRQE; + enable_irq(s->irqs[SCIx_RXI_IRQ]); + } + serial_port_out(port, SCSCR, scr | SCSCR_RIE); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static struct dma_chan *sci_request_dma_chan(struct uart_port *port, + enum dma_transfer_direction dir, + unsigned int id) +{ + dma_cap_mask_t mask; + struct dma_chan *chan; + struct dma_slave_config cfg; + int ret; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + chan = dma_request_slave_channel_compat(mask, shdma_chan_filter, + (void *)(unsigned long)id, port->dev, + dir == DMA_MEM_TO_DEV ? "tx" : "rx"); + if (!chan) { + dev_warn(port->dev, + "dma_request_slave_channel_compat failed\n"); + return NULL; + } + + memset(&cfg, 0, sizeof(cfg)); + cfg.direction = dir; + if (dir == DMA_MEM_TO_DEV) { + cfg.dst_addr = port->mapbase + + (sci_getreg(port, SCxTDR)->offset << port->regshift); + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + } else { + cfg.src_addr = port->mapbase + + (sci_getreg(port, SCxRDR)->offset << port->regshift); + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + } + + ret = dmaengine_slave_config(chan, &cfg); + if (ret) { + dev_warn(port->dev, "dmaengine_slave_config failed %d\n", ret); + dma_release_channel(chan); + return NULL; + } + + return chan; +} + +static void sci_request_dma(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + struct dma_chan *chan; + + dev_dbg(port->dev, "%s: port %d\n", __func__, port->line); + + if (!port->dev->of_node && + (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0)) + return; + + s->cookie_tx = -EINVAL; + chan = sci_request_dma_chan(port, DMA_MEM_TO_DEV, s->cfg->dma_slave_tx); + dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); + if (chan) { + s->chan_tx = chan; + /* UART circular tx buffer is an aligned page. */ + s->tx_dma_addr = dma_map_single(chan->device->dev, + port->state->xmit.buf, + UART_XMIT_SIZE, + DMA_TO_DEVICE); + if (dma_mapping_error(chan->device->dev, s->tx_dma_addr)) { + dev_warn(port->dev, "Failed mapping Tx DMA descriptor\n"); + dma_release_channel(chan); + s->chan_tx = NULL; + } else { + dev_dbg(port->dev, "%s: mapped %lu@%p to %pad\n", + __func__, UART_XMIT_SIZE, + port->state->xmit.buf, &s->tx_dma_addr); + } + + INIT_WORK(&s->work_tx, work_fn_tx); + } + + chan = sci_request_dma_chan(port, DMA_DEV_TO_MEM, s->cfg->dma_slave_rx); + dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); + if (chan) { + unsigned int i; + dma_addr_t dma; + void *buf; + + s->chan_rx = chan; + + s->buf_len_rx = 2 * max_t(size_t, 16, port->fifosize); + buf = dma_alloc_coherent(chan->device->dev, s->buf_len_rx * 2, + &dma, GFP_KERNEL); + if (!buf) { + dev_warn(port->dev, + "Failed to allocate Rx dma buffer, using PIO\n"); + dma_release_channel(chan); + s->chan_rx = NULL; + return; + } + + for (i = 0; i < 2; i++) { + struct scatterlist *sg = &s->sg_rx[i]; + + sg_init_table(sg, 1); + s->rx_buf[i] = buf; + sg_dma_address(sg) = dma; + sg_dma_len(sg) = s->buf_len_rx; + + buf += s->buf_len_rx; + dma += s->buf_len_rx; + } + + setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s); + + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) + sci_submit_rx(s); + } +} + +static void sci_free_dma(struct uart_port *port) +{ + struct sci_port *s = to_sci_port(port); + + if (s->chan_tx) + sci_tx_dma_release(s, false); + if (s->chan_rx) + sci_rx_dma_release(s, false); +} +#else +static inline void sci_request_dma(struct uart_port *port) +{ +} + +static inline void sci_free_dma(struct uart_port *port) +{ +} +#endif + static irqreturn_t sci_rx_interrupt(int irq, void *ptr) { #ifdef CONFIG_SERIAL_SH_SCI_DMA @@ -932,10 +1485,12 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) scr |= SCSCR_RDRQE; } else { scr &= ~SCSCR_RIE; + sci_submit_rx(s); } serial_port_out(port, SCSCR, scr); /* Clear current interrupt */ - serial_port_out(port, SCxSR, ssr & ~(1 | SCxSR_RDxF(port))); + serial_port_out(port, SCxSR, + ssr & ~(SCIF_DR | SCxSR_RDxF(port))); dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n", jiffies, s->rx_timeout); mod_timer(&s->rx_timer, jiffies + s->rx_timeout); @@ -968,23 +1523,26 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr) static irqreturn_t sci_er_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; + struct sci_port *s = to_sci_port(port); /* Handle errors */ if (port->type == PORT_SCI) { if (sci_handle_errors(port)) { /* discard character in rx buffer */ serial_port_in(port, SCxSR); - serial_port_out(port, SCxSR, SCxSR_RDxF_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); } } else { sci_handle_fifo_overrun(port); - sci_rx_interrupt(irq, ptr); + if (!s->chan_rx) + sci_receive_chars(ptr); } - serial_port_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); /* Kick the transmission */ - sci_tx_interrupt(irq, ptr); + if (!s->chan_tx) + sci_tx_interrupt(irq, ptr); return IRQ_HANDLED; } @@ -995,23 +1553,11 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr) /* Handle BREAKs */ sci_handle_breaks(port); - serial_port_out(port, SCxSR, SCxSR_BREAK_CLEAR(port)); + sci_clear_SCxSR(port, SCxSR_BREAK_CLEAR(port)); return IRQ_HANDLED; } -static inline unsigned long port_rx_irq_mask(struct uart_port *port) -{ - /* - * Not all ports (such as SCIFA) will support REIE. Rather than - * special-casing the port type, we check the port initialization - * IRQ enable mask to see whether the IRQ is desired at all. If - * it's unset, it's logically inferred that there's no point in - * testing for it. - */ - return SCSCR_RIE | (to_sci_port(port)->cfg->scscr & SCSCR_REIE); -} - static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) { unsigned short ssr_status, scr_status, err_enabled, orer_status = 0; @@ -1021,15 +1567,11 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) ssr_status = serial_port_in(port, SCxSR); scr_status = serial_port_in(port, SCSCR); - switch (port->type) { - case PORT_SCIF: - case PORT_HSCIF: - orer_status = serial_port_in(port, SCLSR); - break; - case PORT_SCIFA: - case PORT_SCIFB: + if (s->overrun_reg == SCxSR) orer_status = ssr_status; - break; + else { + if (sci_getreg(port, s->overrun_reg)->size) + orer_status = serial_port_in(port, s->overrun_reg); } err_enabled = scr_status & port_rx_irq_mask(port); @@ -1044,11 +1586,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) * DR flags */ if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) && - (scr_status & SCSCR_RIE)) { - if (port->type == PORT_SCIF || port->type == PORT_HSCIF) - sci_handle_fifo_overrun(port); + (scr_status & SCSCR_RIE)) ret = sci_rx_interrupt(irq, ptr); - } /* Error Interrupt */ if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled) @@ -1059,8 +1598,10 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr) ret = sci_br_interrupt(irq, ptr); /* Overrun Interrupt */ - if (orer_status & (1 << s->overrun_bit)) + if (orer_status & s->overrun_mask) { sci_handle_fifo_overrun(port); + ret = IRQ_HANDLED; + } return ret; } @@ -1088,7 +1629,7 @@ static int sci_notifier(struct notifier_block *self, return NOTIFY_OK; } -static struct sci_irq_desc { +static const struct sci_irq_desc { const char *desc; irq_handler_t handler; } sci_irq_desc[] = { @@ -1130,7 +1671,7 @@ static int sci_request_irq(struct sci_port *port) int i, j, ret = 0; for (i = j = 0; i < SCIx_NR_IRQS; i++, j++) { - struct sci_irq_desc *desc; + const struct sci_irq_desc *desc; int irq; if (SCIx_IRQ_IS_MUXED(port)) { @@ -1150,11 +1691,8 @@ static int sci_request_irq(struct sci_port *port) desc = sci_irq_desc + i; port->irqstr[j] = kasprintf(GFP_KERNEL, "%s:%s", dev_name(up->dev), desc->desc); - if (!port->irqstr[j]) { - dev_err(up->dev, "Failed to allocate %s IRQ string\n", - desc->desc); + if (!port->irqstr[j]) goto out_nomem; - } ret = request_irq(irq, desc->handler, up->irqflags, port->irqstr[j], port); @@ -1228,7 +1766,7 @@ static unsigned int sci_tx_empty(struct uart_port *port) static void sci_set_mctrl(struct uart_port *port, unsigned int mctrl) { if (mctrl & TIOCM_LOOP) { - struct plat_sci_reg *reg; + const struct plat_sci_reg *reg; /* * Standard loopback mode for SCFCR ports. @@ -1250,356 +1788,10 @@ static unsigned int sci_get_mctrl(struct uart_port *port) return TIOCM_DSR | TIOCM_CAR; } -#ifdef CONFIG_SERIAL_SH_SCI_DMA -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; - unsigned long flags; - - dev_dbg(port->dev, "%s(%d)\n", __func__, port->line); - - spin_lock_irqsave(&port->lock, flags); - - xmit->tail += sg_dma_len(&s->sg_tx); - xmit->tail &= UART_XMIT_SIZE - 1; - - port->icount.tx += sg_dma_len(&s->sg_tx); - - async_tx_ack(s->desc_tx); - s->desc_tx = NULL; - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (!uart_circ_empty(xmit)) { - s->cookie_tx = 0; - schedule_work(&s->work_tx); - } else { - s->cookie_tx = -EINVAL; - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 ctrl = serial_port_in(port, SCSCR); - serial_port_out(port, SCSCR, ctrl & ~SCSCR_TIE); - } - } - - spin_unlock_irqrestore(&port->lock, flags); -} - -/* Locking: called with port lock held */ -static int sci_dma_rx_push(struct sci_port *s, size_t count) -{ - struct uart_port *port = &s->port; - struct tty_port *tport = &port->state->port; - int i, active, room; - - room = tty_buffer_request_room(tport, count); - - if (s->active_rx == s->cookie_rx[0]) { - active = 0; - } else if (s->active_rx == s->cookie_rx[1]) { - active = 1; - } else { - dev_err(port->dev, "cookie %d not found!\n", s->active_rx); - return 0; - } - - if (room < count) - dev_warn(port->dev, "Rx overrun: dropping %zu bytes\n", - count - room); - if (!room) - return room; - - for (i = 0; i < room; i++) - tty_insert_flip_char(tport, ((u8 *)sg_virt(&s->sg_rx[active]))[i], - TTY_NORMAL); - - port->icount.rx += room; - - return room; -} - -static void sci_dma_rx_complete(void *arg) -{ - struct sci_port *s = arg; - struct uart_port *port = &s->port; - unsigned long flags; - int count; - - dev_dbg(port->dev, "%s(%d) active #%d\n", - __func__, port->line, s->active_rx); - - spin_lock_irqsave(&port->lock, flags); - - count = sci_dma_rx_push(s, s->buf_len_rx); - - mod_timer(&s->rx_timer, jiffies + s->rx_timeout); - - spin_unlock_irqrestore(&port->lock, flags); - - if (count) - tty_flip_buffer_push(&port->state->port); - - schedule_work(&s->work_rx); -} - -static void sci_rx_dma_release(struct sci_port *s, bool enable_pio) -{ - struct dma_chan *chan = s->chan_rx; - struct uart_port *port = &s->port; - - s->chan_rx = NULL; - s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; - dma_release_channel(chan); - if (sg_dma_address(&s->sg_rx[0])) - dma_free_coherent(port->dev, s->buf_len_rx * 2, - sg_virt(&s->sg_rx[0]), sg_dma_address(&s->sg_rx[0])); - if (enable_pio) - sci_start_rx(port); -} - -static void sci_tx_dma_release(struct sci_port *s, bool enable_pio) -{ - struct dma_chan *chan = s->chan_tx; - struct uart_port *port = &s->port; - - s->chan_tx = NULL; - s->cookie_tx = -EINVAL; - dma_release_channel(chan); - if (enable_pio) - sci_start_tx(port); -} - -static void sci_submit_rx(struct sci_port *s) -{ - struct dma_chan *chan = s->chan_rx; - int i; - - for (i = 0; i < 2; i++) { - struct scatterlist *sg = &s->sg_rx[i]; - struct dma_async_tx_descriptor *desc; - - desc = dmaengine_prep_slave_sg(chan, - sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); - - if (desc) { - s->desc_rx[i] = desc; - desc->callback = sci_dma_rx_complete; - desc->callback_param = s; - s->cookie_rx[i] = desc->tx_submit(desc); - } - - if (!desc || s->cookie_rx[i] < 0) { - if (i) { - async_tx_ack(s->desc_rx[0]); - s->cookie_rx[0] = -EINVAL; - } - if (desc) { - async_tx_ack(desc); - s->cookie_rx[i] = -EINVAL; - } - dev_warn(s->port.dev, - "failed to re-start DMA, using PIO\n"); - sci_rx_dma_release(s, true); - return; - } - dev_dbg(s->port.dev, "%s(): cookie %d to #%d\n", - __func__, s->cookie_rx[i], i); - } - - s->active_rx = s->cookie_rx[0]; - - dma_async_issue_pending(chan); -} - -static void work_fn_rx(struct work_struct *work) -{ - struct sci_port *s = container_of(work, struct sci_port, work_rx); - struct uart_port *port = &s->port; - struct dma_async_tx_descriptor *desc; - int new; - - if (s->active_rx == s->cookie_rx[0]) { - new = 0; - } else if (s->active_rx == s->cookie_rx[1]) { - new = 1; - } else { - dev_err(port->dev, "cookie %d not found!\n", s->active_rx); - return; - } - desc = s->desc_rx[new]; - - if (dma_async_is_tx_complete(s->chan_rx, s->active_rx, NULL, NULL) != - DMA_COMPLETE) { - /* Handle incomplete DMA receive */ - struct dma_chan *chan = s->chan_rx; - struct shdma_desc *sh_desc = container_of(desc, - struct shdma_desc, async_tx); - unsigned long flags; - int count; - - dmaengine_terminate_all(chan); - dev_dbg(port->dev, "Read %zu bytes with cookie %d\n", - sh_desc->partial, sh_desc->cookie); - - spin_lock_irqsave(&port->lock, flags); - count = sci_dma_rx_push(s, sh_desc->partial); - spin_unlock_irqrestore(&port->lock, flags); - - if (count) - tty_flip_buffer_push(&port->state->port); - - sci_submit_rx(s); - - return; - } - - s->cookie_rx[new] = desc->tx_submit(desc); - if (s->cookie_rx[new] < 0) { - dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); - sci_rx_dma_release(s, true); - return; - } - - s->active_rx = s->cookie_rx[!new]; - - dev_dbg(port->dev, "%s: cookie %d #%d, new active #%d\n", - __func__, s->cookie_rx[new], new, s->active_rx); -} - -static void work_fn_tx(struct work_struct *work) -{ - struct sci_port *s = container_of(work, struct sci_port, work_tx); - 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 scatterlist *sg = &s->sg_tx; - - /* - * DMA is idle now. - * Port xmit buffer is already mapped, and it is one page... Just adjust - * offsets and lengths. Since it is a circular buffer, we have to - * transmit till the end, and then the rest. Take the port lock to get a - * consistent xmit buffer state. - */ - spin_lock_irq(&port->lock); - sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); - sg_dma_address(sg) = (sg_dma_address(sg) & ~(UART_XMIT_SIZE - 1)) + - sg->offset; - sg_dma_len(sg) = min((int)CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE), - CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE)); - spin_unlock_irq(&port->lock); - - BUG_ON(!sg_dma_len(sg)); - - desc = dmaengine_prep_slave_sg(chan, - sg, s->sg_len_tx, DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK); - if (!desc) { - /* switch to PIO */ - sci_tx_dma_release(s, true); - return; - } - - dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); - - spin_lock_irq(&port->lock); - s->desc_tx = desc; - desc->callback = sci_dma_tx_complete; - desc->callback_param = s; - spin_unlock_irq(&port->lock); - s->cookie_tx = desc->tx_submit(desc); - if (s->cookie_tx < 0) { - dev_warn(port->dev, "Failed submitting Tx DMA descriptor\n"); - /* switch to PIO */ - sci_tx_dma_release(s, true); - return; - } - - dev_dbg(port->dev, "%s: %p: %d...%d, cookie %d\n", - __func__, xmit->buf, xmit->tail, xmit->head, s->cookie_tx); - - dma_async_issue_pending(chan); -} -#endif - -static void sci_start_tx(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - unsigned short ctrl; - -#ifdef CONFIG_SERIAL_SH_SCI_DMA - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - u16 new, scr = serial_port_in(port, SCSCR); - if (s->chan_tx) - new = scr | SCSCR_TDRQE; - else - new = scr & ~SCSCR_TDRQE; - if (new != scr) - serial_port_out(port, SCSCR, new); - } - - if (s->chan_tx && !uart_circ_empty(&s->port.state->xmit) && - s->cookie_tx < 0) { - s->cookie_tx = 0; - schedule_work(&s->work_tx); - } -#endif - - if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = serial_port_in(port, SCSCR); - serial_port_out(port, SCSCR, ctrl | SCSCR_TIE); - } -} - -static void sci_stop_tx(struct uart_port *port) -{ - unsigned short ctrl; - - /* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */ - ctrl = serial_port_in(port, SCSCR); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~SCSCR_TDRQE; - - ctrl &= ~SCSCR_TIE; - - serial_port_out(port, SCSCR, ctrl); -} - -static void sci_start_rx(struct uart_port *port) -{ - unsigned short ctrl; - - ctrl = serial_port_in(port, SCSCR) | port_rx_irq_mask(port); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~SCSCR_RDRQE; - - serial_port_out(port, SCSCR, ctrl); -} - -static void sci_stop_rx(struct uart_port *port) -{ - unsigned short ctrl; - - ctrl = serial_port_in(port, SCSCR); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - ctrl &= ~SCSCR_RDRQE; - - ctrl &= ~port_rx_irq_mask(port); - - serial_port_out(port, SCSCR, ctrl); -} - static void sci_break_ctl(struct uart_port *port, int break_state) { struct sci_port *s = to_sci_port(port); - struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; + const struct plat_sci_reg *reg = sci_regmap[s->cfg->regtype] + SCSPTR; unsigned short scscr, scsptr; /* check wheter the port has SCSPTR */ @@ -1626,142 +1818,6 @@ static void sci_break_ctl(struct uart_port *port, int break_state) serial_port_out(port, SCSCR, scscr); } -#ifdef CONFIG_SERIAL_SH_SCI_DMA -static bool filter(struct dma_chan *chan, void *slave) -{ - struct sh_dmae_slave *param = slave; - - dev_dbg(chan->device->dev, "%s: slave ID %d\n", - __func__, param->shdma_slave.slave_id); - - chan->private = ¶m->shdma_slave; - return true; -} - -static void rx_timer_fn(unsigned long arg) -{ - struct sci_port *s = (struct sci_port *)arg; - struct uart_port *port = &s->port; - u16 scr = serial_port_in(port, SCSCR); - - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - scr &= ~SCSCR_RDRQE; - enable_irq(s->irqs[SCIx_RXI_IRQ]); - } - serial_port_out(port, SCSCR, scr | SCSCR_RIE); - dev_dbg(port->dev, "DMA Rx timed out\n"); - schedule_work(&s->work_rx); -} - -static void sci_request_dma(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - struct sh_dmae_slave *param; - struct dma_chan *chan; - dma_cap_mask_t mask; - int nent; - - dev_dbg(port->dev, "%s: port %d\n", __func__, port->line); - - if (s->cfg->dma_slave_tx <= 0 || s->cfg->dma_slave_rx <= 0) - return; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - - param = &s->param_tx; - - /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_TX */ - param->shdma_slave.slave_id = s->cfg->dma_slave_tx; - - s->cookie_tx = -EINVAL; - chan = dma_request_channel(mask, filter, param); - dev_dbg(port->dev, "%s: TX: got channel %p\n", __func__, chan); - if (chan) { - s->chan_tx = chan; - sg_init_table(&s->sg_tx, 1); - /* UART circular tx buffer is an aligned page. */ - BUG_ON((uintptr_t)port->state->xmit.buf & ~PAGE_MASK); - sg_set_page(&s->sg_tx, virt_to_page(port->state->xmit.buf), - UART_XMIT_SIZE, - (uintptr_t)port->state->xmit.buf & ~PAGE_MASK); - nent = dma_map_sg(port->dev, &s->sg_tx, 1, DMA_TO_DEVICE); - if (!nent) - sci_tx_dma_release(s, false); - else - dev_dbg(port->dev, "%s: mapped %d@%p to %pad\n", - __func__, - sg_dma_len(&s->sg_tx), port->state->xmit.buf, - &sg_dma_address(&s->sg_tx)); - - s->sg_len_tx = nent; - - INIT_WORK(&s->work_tx, work_fn_tx); - } - - param = &s->param_rx; - - /* Slave ID, e.g., SHDMA_SLAVE_SCIF0_RX */ - param->shdma_slave.slave_id = s->cfg->dma_slave_rx; - - chan = dma_request_channel(mask, filter, param); - dev_dbg(port->dev, "%s: RX: got channel %p\n", __func__, chan); - if (chan) { - dma_addr_t dma[2]; - void *buf[2]; - int i; - - s->chan_rx = chan; - - s->buf_len_rx = 2 * max(16, (int)port->fifosize); - buf[0] = dma_alloc_coherent(port->dev, s->buf_len_rx * 2, - &dma[0], GFP_KERNEL); - - if (!buf[0]) { - dev_warn(port->dev, - "failed to allocate dma buffer, using PIO\n"); - sci_rx_dma_release(s, true); - return; - } - - buf[1] = buf[0] + s->buf_len_rx; - dma[1] = dma[0] + s->buf_len_rx; - - for (i = 0; i < 2; i++) { - struct scatterlist *sg = &s->sg_rx[i]; - - sg_init_table(sg, 1); - sg_set_page(sg, virt_to_page(buf[i]), s->buf_len_rx, - (uintptr_t)buf[i] & ~PAGE_MASK); - sg_dma_address(sg) = dma[i]; - } - - INIT_WORK(&s->work_rx, work_fn_rx); - setup_timer(&s->rx_timer, rx_timer_fn, (unsigned long)s); - - sci_submit_rx(s); - } -} - -static void sci_free_dma(struct uart_port *port) -{ - struct sci_port *s = to_sci_port(port); - - if (s->chan_tx) - sci_tx_dma_release(s, false); - if (s->chan_rx) - sci_rx_dma_release(s, false); -} -#else -static inline void sci_request_dma(struct uart_port *port) -{ -} - -static inline void sci_free_dma(struct uart_port *port) -{ -} -#endif - static int sci_startup(struct uart_port *port) { struct sci_port *s = to_sci_port(port); @@ -1796,6 +1852,14 @@ static void sci_shutdown(struct uart_port *port) sci_stop_tx(port); spin_unlock_irqrestore(&port->lock, flags); +#ifdef CONFIG_SERIAL_SH_SCI_DMA + if (s->chan_rx) { + dev_dbg(port->dev, "%s(%d) deleting rx_timer\n", __func__, + port->line); + del_timer_sync(&s->rx_timer); + } +#endif + sci_free_dma(port); sci_free_irq(s); } @@ -1888,7 +1952,7 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, static void sci_reset(struct uart_port *port) { - struct plat_sci_reg *reg; + const struct plat_sci_reg *reg; unsigned int status; do { @@ -1906,7 +1970,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct sci_port *s = to_sci_port(port); - struct plat_sci_reg *reg; + const struct plat_sci_reg *reg; unsigned int baud, smr_val = 0, max_baud, cks = 0; int t = -1; unsigned int srr = 15; @@ -1947,7 +2011,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, sci_reset(port); - smr_val |= serial_port_in(port, SCSMR) & 3; + smr_val |= serial_port_in(port, SCSMR) & SCSMR_CKS; uart_update_timeout(port, termios->c_cflag, baud); @@ -1992,13 +2056,13 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios, #ifdef CONFIG_SERIAL_SH_SCI_DMA /* * Calculate delay for 2 DMA buffers (4 FIFO). - * See drivers/serial/serial_core.c::uart_update_timeout(). With 10 - * bits (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above function - * calculates 1 jiffie for the data plus 5 jiffies for the "slop(e)." - * Then below we calculate 5 jiffies (20ms) for 2 DMA buffers (4 FIFO - * sizes), but when performing a faster transfer, value obtained by - * this formula is may not enough. Therefore, if value is smaller than - * 20msec, this sets 20msec as timeout of DMA. + * See serial_core.c::uart_update_timeout(). + * With 10 bits (CS8), 250Hz, 115200 baud and 64 bytes FIFO, the above + * function calculates 1 jiffie for the data plus 5 jiffies for the + * "slop(e)." Then below we calculate 5 jiffies (20ms) for 2 DMA + * buffers (4 FIFO sizes), but when performing a faster transfer, the + * value obtained by this formula is too small. Therefore, if the value + * is smaller than 20ms, use 20ms as the timeout value for DMA. */ if (s->chan_rx) { unsigned int bits; @@ -2073,23 +2137,9 @@ static const char *sci_type(struct uart_port *port) return NULL; } -static inline unsigned long sci_port_size(struct uart_port *port) -{ - /* - * Pick an arbitrary size that encapsulates all of the base - * registers by default. This can be optimized later, or derived - * from platform resource data at such a time that ports begin to - * behave more erratically. - */ - if (port->type == PORT_HSCIF) - return 96; - else - return 64; -} - static int sci_remap_port(struct uart_port *port) { - unsigned long size = sci_port_size(port); + struct sci_port *sport = to_sci_port(port); /* * Nothing to do if there's already an established membase. @@ -2098,7 +2148,7 @@ static int sci_remap_port(struct uart_port *port) return 0; if (port->flags & UPF_IOREMAP) { - port->membase = ioremap_nocache(port->mapbase, size); + port->membase = ioremap_nocache(port->mapbase, sport->reg_size); if (unlikely(!port->membase)) { dev_err(port->dev, "can't remap port#%d\n", port->line); return -ENXIO; @@ -2117,23 +2167,28 @@ static int sci_remap_port(struct uart_port *port) static void sci_release_port(struct uart_port *port) { + struct sci_port *sport = to_sci_port(port); + if (port->flags & UPF_IOREMAP) { iounmap(port->membase); port->membase = NULL; } - release_mem_region(port->mapbase, sci_port_size(port)); + release_mem_region(port->mapbase, sport->reg_size); } static int sci_request_port(struct uart_port *port) { - unsigned long size = sci_port_size(port); struct resource *res; + struct sci_port *sport = to_sci_port(port); int ret; - res = request_mem_region(port->mapbase, size, dev_name(port->dev)); - if (unlikely(res == NULL)) + res = request_mem_region(port->mapbase, sport->reg_size, + dev_name(port->dev)); + if (unlikely(res == NULL)) { + dev_err(port->dev, "request_mem_region failed."); return -EBUSY; + } ret = sci_remap_port(port); if (unlikely(ret != 0)) { @@ -2192,7 +2247,6 @@ static int sci_init_single(struct platform_device *dev, { struct uart_port *port = &sci_port->port; const struct resource *res; - unsigned int sampling_rate; unsigned int i; int ret; @@ -2207,6 +2261,7 @@ static int sci_init_single(struct platform_device *dev, return -ENOMEM; port->mapbase = res->start; + sci_port->reg_size = resource_size(res); for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) sci_port->irqs[i] = platform_get_irq(dev, i); @@ -2234,33 +2289,39 @@ static int sci_init_single(struct platform_device *dev, switch (p->type) { case PORT_SCIFB: port->fifosize = 256; - sci_port->overrun_bit = 9; - sampling_rate = 16; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCIFA_ORER; + sci_port->sampling_rate = 16; break; case PORT_HSCIF: port->fifosize = 128; - sampling_rate = 0; - sci_port->overrun_bit = 0; + sci_port->overrun_reg = SCLSR; + sci_port->overrun_mask = SCLSR_ORER; + sci_port->sampling_rate = 0; break; case PORT_SCIFA: port->fifosize = 64; - sci_port->overrun_bit = 9; - sampling_rate = 16; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCIFA_ORER; + sci_port->sampling_rate = 16; break; case PORT_SCIF: port->fifosize = 16; if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) { - sci_port->overrun_bit = 9; - sampling_rate = 16; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCIFA_ORER; + sci_port->sampling_rate = 16; } else { - sci_port->overrun_bit = 0; - sampling_rate = 32; + sci_port->overrun_reg = SCLSR; + sci_port->overrun_mask = SCLSR_ORER; + sci_port->sampling_rate = 32; } break; default: port->fifosize = 1; - sci_port->overrun_bit = 5; - sampling_rate = 32; + sci_port->overrun_reg = SCxSR; + sci_port->overrun_mask = SCI_ORER; + sci_port->sampling_rate = 32; break; } @@ -2268,8 +2329,8 @@ static int sci_init_single(struct platform_device *dev, * match the SoC datasheet, this should be investigated. Let platform * data override the sampling rate for now. */ - sci_port->sampling_rate = p->sampling_rate ? p->sampling_rate - : sampling_rate; + if (p->sampling_rate) + sci_port->sampling_rate = p->sampling_rate; if (!early) { sci_port->iclk = clk_get(&dev->dev, "sci_ick"); @@ -2301,19 +2362,22 @@ static int sci_init_single(struct platform_device *dev, /* * Establish some sensible defaults for the error detection. */ - sci_port->error_mask = (p->type == PORT_SCI) ? - SCI_DEFAULT_ERROR_MASK : SCIF_DEFAULT_ERROR_MASK; - - /* - * Establish sensible defaults for the overrun detection, unless - * the part has explicitly disabled support for it. - */ + if (p->type == PORT_SCI) { + sci_port->error_mask = SCI_DEFAULT_ERROR_MASK; + sci_port->error_clear = SCI_ERROR_CLEAR; + } else { + sci_port->error_mask = SCIF_DEFAULT_ERROR_MASK; + sci_port->error_clear = SCIF_ERROR_CLEAR; + } /* * Make the error mask inclusive of overrun detection, if * supported. */ - sci_port->error_mask |= 1 << sci_port->overrun_bit; + if (sci_port->overrun_reg == SCxSR) { + sci_port->error_mask |= sci_port->overrun_mask; + sci_port->error_clear &= ~sci_port->overrun_mask; + } port->type = p->type; port->flags = UPF_FIXED_PORT | p->flags; @@ -2536,6 +2600,12 @@ static const struct of_device_id of_sci_match[] = { .regtype = SCIx_HSCIF_REGTYPE, }, }, { + .compatible = "renesas,sci", + .data = &(const struct sci_port_info) { + .type = PORT_SCI, + .regtype = SCIx_SCI_REGTYPE, + }, + }, { /* Terminator */ }, }; @@ -2560,10 +2630,8 @@ sci_parse_dt(struct platform_device *pdev, unsigned int *dev_id) info = match->data; p = devm_kzalloc(&pdev->dev, sizeof(struct plat_sci_port), GFP_KERNEL); - if (!p) { - dev_err(&pdev->dev, "failed to allocate DT config data\n"); + if (!p) return NULL; - } /* Get the line number for the aliases node. */ id = of_alias_get_id(np, "serial"); diff --git a/kernel/drivers/tty/serial/sh-sci.h b/kernel/drivers/tty/serial/sh-sci.h index d5db81a0a..bf69bbdcc 100644 --- a/kernel/drivers/tty/serial/sh-sci.h +++ b/kernel/drivers/tty/serial/sh-sci.h @@ -1,7 +1,115 @@ +#include <linux/bitops.h> #include <linux/serial_core.h> #include <linux/io.h> #include <linux/gpio.h> +#define SCI_MAJOR 204 +#define SCI_MINOR_START 8 + + +/* + * SCI register subset common for all port types. + * Not all registers will exist on all parts. + */ +enum { + SCSMR, /* Serial Mode Register */ + SCBRR, /* Bit Rate Register */ + SCSCR, /* Serial Control Register */ + SCxSR, /* Serial Status Register */ + SCFCR, /* FIFO Control Register */ + SCFDR, /* FIFO Data Count Register */ + SCxTDR, /* Transmit (FIFO) Data Register */ + SCxRDR, /* Receive (FIFO) Data Register */ + SCLSR, /* Line Status Register */ + SCTFDR, /* Transmit FIFO Data Count Register */ + SCRFDR, /* Receive FIFO Data Count Register */ + SCSPTR, /* Serial Port Register */ + HSSRR, /* Sampling Rate Register */ + SCPCR, /* Serial Port Control Register */ + SCPDR, /* Serial Port Data Register */ + + SCIx_NR_REGS, +}; + + +/* SCSMR (Serial Mode Register) */ +#define SCSMR_CHR BIT(6) /* 7-bit Character Length */ +#define SCSMR_PE BIT(5) /* Parity Enable */ +#define SCSMR_ODD BIT(4) /* Odd Parity */ +#define SCSMR_STOP BIT(3) /* Stop Bit Length */ +#define SCSMR_CKS 0x0003 /* Clock Select */ + +/* Serial Control Register, SCIFA/SCIFB only bits */ +#define SCSCR_TDRQE BIT(15) /* Tx Data Transfer Request Enable */ +#define SCSCR_RDRQE BIT(14) /* Rx Data Transfer Request Enable */ + +/* SCxSR (Serial Status Register) on SCI */ +#define SCI_TDRE BIT(7) /* Transmit Data Register Empty */ +#define SCI_RDRF BIT(6) /* Receive Data Register Full */ +#define SCI_ORER BIT(5) /* Overrun Error */ +#define SCI_FER BIT(4) /* Framing Error */ +#define SCI_PER BIT(3) /* Parity Error */ +#define SCI_TEND BIT(2) /* Transmit End */ +#define SCI_RESERVED 0x03 /* All reserved bits */ + +#define SCI_DEFAULT_ERROR_MASK (SCI_PER | SCI_FER) + +#define SCI_RDxF_CLEAR (u32)(~(SCI_RESERVED | SCI_RDRF)) +#define SCI_ERROR_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)) +#define SCI_TDxE_CLEAR (u32)(~(SCI_RESERVED | SCI_TEND | SCI_TDRE)) +#define SCI_BREAK_CLEAR (u32)(~(SCI_RESERVED | SCI_PER | SCI_FER | SCI_ORER)) + +/* SCxSR (Serial Status Register) on SCIF, SCIFA, SCIFB, HSCIF */ +#define SCIF_ER BIT(7) /* Receive Error */ +#define SCIF_TEND BIT(6) /* Transmission End */ +#define SCIF_TDFE BIT(5) /* Transmit FIFO Data Empty */ +#define SCIF_BRK BIT(4) /* Break Detect */ +#define SCIF_FER BIT(3) /* Framing Error */ +#define SCIF_PER BIT(2) /* Parity Error */ +#define SCIF_RDF BIT(1) /* Receive FIFO Data Full */ +#define SCIF_DR BIT(0) /* Receive Data Ready */ +/* SCIF only (optional) */ +#define SCIF_PERC 0xf000 /* Number of Parity Errors */ +#define SCIF_FERC 0x0f00 /* Number of Framing Errors */ +/*SCIFA/SCIFB and SCIF on SH7705/SH7720/SH7721 only */ +#define SCIFA_ORER BIT(9) /* Overrun Error */ + +#define SCIF_DEFAULT_ERROR_MASK (SCIF_PER | SCIF_FER | SCIF_BRK | SCIF_ER) + +#define SCIF_RDxF_CLEAR (u32)(~(SCIF_DR | SCIF_RDF)) +#define SCIF_ERROR_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_ER)) +#define SCIF_TDxE_CLEAR (u32)(~(SCIF_TDFE)) +#define SCIF_BREAK_CLEAR (u32)(~(SCIF_PER | SCIF_FER | SCIF_BRK)) + +/* SCFCR (FIFO Control Register) */ +#define SCFCR_MCE BIT(3) /* Modem Control Enable */ +#define SCFCR_TFRST BIT(2) /* Transmit FIFO Data Register Reset */ +#define SCFCR_RFRST BIT(1) /* Receive FIFO Data Register Reset */ +#define SCFCR_LOOP BIT(0) /* Loopback Test */ + +/* SCLSR (Line Status Register) on (H)SCIF */ +#define SCLSR_ORER BIT(0) /* Overrun Error */ + +/* SCSPTR (Serial Port Register), optional */ +#define SCSPTR_RTSIO BIT(7) /* Serial Port RTS Pin Input/Output */ +#define SCSPTR_RTSDT BIT(6) /* Serial Port RTS Pin Data */ +#define SCSPTR_CTSIO BIT(5) /* Serial Port CTS Pin Input/Output */ +#define SCSPTR_CTSDT BIT(4) /* Serial Port CTS Pin Data */ +#define SCSPTR_SPB2IO BIT(1) /* Serial Port Break Input/Output */ +#define SCSPTR_SPB2DT BIT(0) /* Serial Port Break Data */ + +/* HSSRR HSCIF */ +#define HSCIF_SRE BIT(15) /* Sampling Rate Register Enable */ + +/* SCPCR (Serial Port Control Register), SCIFA/SCIFB only */ +#define SCPCR_RTSC BIT(4) /* Serial Port RTS Pin / Output Pin */ +#define SCPCR_CTSC BIT(3) /* Serial Port CTS Pin / Input Pin */ + +/* SCPDR (Serial Port Data Register), SCIFA/SCIFB only */ +#define SCPDR_RTSD BIT(4) /* Serial Port RTS Output Pin Data */ +#define SCPDR_CTSD BIT(3) /* Serial Port CTS Input Pin Data */ + + #define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND) #define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF) #define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE) @@ -11,28 +119,11 @@ #define SCxSR_ERRORS(port) (to_sci_port(port)->error_mask) -#if defined(CONFIG_CPU_SUBTYPE_SH7705) || \ - defined(CONFIG_CPU_SUBTYPE_SH7720) || \ - defined(CONFIG_CPU_SUBTYPE_SH7721) || \ - defined(CONFIG_ARCH_SH73A0) || \ - defined(CONFIG_ARCH_SH7372) || \ - defined(CONFIG_ARCH_R8A7740) - -# define SCxSR_RDxF_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfffc) -# define SCxSR_ERROR_CLEAR(port) (serial_port_in(port, SCxSR) & 0xfd73) -# define SCxSR_TDxE_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffdf) -# define SCxSR_BREAK_CLEAR(port) (serial_port_in(port, SCxSR) & 0xffe3) -#else -# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc) -# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073) -# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df) -# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3) -#endif - -/* SCFCR */ -#define SCFCR_RFRST 0x0002 -#define SCFCR_TFRST 0x0004 -#define SCFCR_MCE 0x0008 - -#define SCI_MAJOR 204 -#define SCI_MINOR_START 8 +#define SCxSR_RDxF_CLEAR(port) \ + (((port)->type == PORT_SCI) ? SCI_RDxF_CLEAR : SCIF_RDxF_CLEAR) +#define SCxSR_ERROR_CLEAR(port) \ + (to_sci_port(port)->error_clear) +#define SCxSR_TDxE_CLEAR(port) \ + (((port)->type == PORT_SCI) ? SCI_TDxE_CLEAR : SCIF_TDxE_CLEAR) +#define SCxSR_BREAK_CLEAR(port) \ + (((port)->type == PORT_SCI) ? SCI_BREAK_CLEAR : SCIF_BREAK_CLEAR) diff --git a/kernel/drivers/tty/serial/sirfsoc_uart.c b/kernel/drivers/tty/serial/sirfsoc_uart.c index 9de3eabe5..c6657de78 100644 --- a/kernel/drivers/tty/serial/sirfsoc_uart.c +++ b/kernel/drivers/tty/serial/sirfsoc_uart.c @@ -36,8 +36,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count); static struct uart_driver sirfsoc_uart_drv; static void sirfsoc_uart_tx_dma_complete_callback(void *param); -static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port); -static void sirfsoc_uart_rx_dma_complete_callback(void *param); static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = { {4000000, 2359296}, {3500000, 1310721}, @@ -59,50 +57,7 @@ static const struct sirfsoc_baudrate_to_regv baudrate_to_regv[] = { {9600, 1114979}, }; -static struct sirfsoc_uart_port sirfsoc_uart_ports[SIRFSOC_UART_NR] = { - [0] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 0, - }, - }, - [1] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 1, - }, - }, - [2] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 2, - }, - }, - [3] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 3, - }, - }, - [4] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 4, - }, - }, - [5] = { - .port = { - .iotype = UPIO_MEM, - .flags = UPF_BOOT_AUTOCONF, - .line = 5, - }, - }, -}; +static struct sirfsoc_uart_port *sirf_ports[SIRFSOC_UART_NR]; static inline struct sirfsoc_uart_port *to_sirfport(struct uart_port *port) { @@ -116,8 +71,7 @@ static inline unsigned int sirfsoc_uart_tx_empty(struct uart_port *port) struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status; reg = rd_regl(port, ureg->sirfsoc_tx_fifo_status); - - return (reg & ufifo_st->ff_empty(port->line)) ? TIOCSER_TEMT : 0; + return (reg & ufifo_st->ff_empty(port)) ? TIOCSER_TEMT : 0; } static unsigned int sirfsoc_uart_get_mctrl(struct uart_port *port) @@ -152,6 +106,26 @@ static void sirfsoc_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) unsigned int val = assert ? SIRFUART_AFC_CTRL_RX_THD : 0x0; unsigned int current_val; + if (mctrl & TIOCM_LOOP) { + if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) + wr_regl(port, ureg->sirfsoc_line_ctrl, + rd_regl(port, ureg->sirfsoc_line_ctrl) | + SIRFUART_LOOP_BACK); + else + wr_regl(port, ureg->sirfsoc_mode1, + rd_regl(port, ureg->sirfsoc_mode1) | + SIRFSOC_USP_LOOP_BACK_CTRL); + } else { + if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) + wr_regl(port, ureg->sirfsoc_line_ctrl, + rd_regl(port, ureg->sirfsoc_line_ctrl) & + ~SIRFUART_LOOP_BACK); + else + wr_regl(port, ureg->sirfsoc_mode1, + rd_regl(port, ureg->sirfsoc_mode1) & + ~SIRFSOC_USP_LOOP_BACK_CTRL); + } + if (!sirfport->hw_flow_ctrl || !sirfport->ms_enabled) return; if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { @@ -182,16 +156,19 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port) rd_regl(port, ureg->sirfsoc_int_en_reg) & ~uint_en->sirfsoc_txfifo_empty_en); else - wr_regl(port, SIRFUART_INT_EN_CLR, + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, uint_en->sirfsoc_txfifo_empty_en); } } else { + if (sirfport->uart_reg->uart_type == SIRF_USP_UART) + wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port, + ureg->sirfsoc_tx_rx_en) & ~SIRFUART_TX_EN); if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) & ~uint_en->sirfsoc_txfifo_empty_en); else - wr_regl(port, SIRFUART_INT_EN_CLR, + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, uint_en->sirfsoc_txfifo_empty_en); } } @@ -222,7 +199,7 @@ static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport) rd_regl(port, ureg->sirfsoc_int_en_reg)& ~(uint_en->sirfsoc_txfifo_empty_en)); else - wr_regl(port, SIRFUART_INT_EN_CLR, + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, uint_en->sirfsoc_txfifo_empty_en); /* * DMA requires buffer address and buffer length are both aligned with @@ -290,8 +267,11 @@ static void sirfsoc_uart_start_tx(struct uart_port *port) if (sirfport->tx_dma_chan) sirfsoc_uart_tx_with_dma(sirfport); else { - sirfsoc_uart_pio_tx_chars(sirfport, - SIRFSOC_UART_IO_TX_REASONABLE_CNT); + if (sirfport->uart_reg->uart_type == SIRF_USP_UART) + wr_regl(port, ureg->sirfsoc_tx_rx_en, rd_regl(port, + ureg->sirfsoc_tx_rx_en) | SIRFUART_TX_EN); + wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP); + sirfsoc_uart_pio_tx_chars(sirfport, port->fifosize); wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START); if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, @@ -314,21 +294,25 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port) if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) & - ~(SIRFUART_RX_DMA_INT_EN(port, uint_en) | + ~(SIRFUART_RX_DMA_INT_EN(uint_en, + sirfport->uart_reg->uart_type) | uint_en->sirfsoc_rx_done_en)); else - wr_regl(port, SIRFUART_INT_EN_CLR, - SIRFUART_RX_DMA_INT_EN(port, uint_en)| - uint_en->sirfsoc_rx_done_en); + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, + SIRFUART_RX_DMA_INT_EN(uint_en, + sirfport->uart_reg->uart_type)| + uint_en->sirfsoc_rx_done_en); dmaengine_terminate_all(sirfport->rx_dma_chan); } else { if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg)& - ~(SIRFUART_RX_IO_INT_EN(port, uint_en))); + ~(SIRFUART_RX_IO_INT_EN(uint_en, + sirfport->uart_reg->uart_type))); else - wr_regl(port, SIRFUART_INT_EN_CLR, - SIRFUART_RX_IO_INT_EN(port, uint_en)); + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, + SIRFUART_RX_IO_INT_EN(uint_en, + sirfport->uart_reg->uart_type)); } } @@ -349,7 +333,7 @@ static void sirfsoc_uart_disable_ms(struct uart_port *port) rd_regl(port, ureg->sirfsoc_int_en_reg)& ~uint_en->sirfsoc_cts_en); else - wr_regl(port, SIRFUART_INT_EN_CLR, + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, uint_en->sirfsoc_cts_en); } else disable_irq(gpio_to_irq(sirfport->cts_gpio)); @@ -379,7 +363,8 @@ static void sirfsoc_uart_enable_ms(struct uart_port *port) if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { wr_regl(port, ureg->sirfsoc_afc_ctrl, rd_regl(port, ureg->sirfsoc_afc_ctrl) | - SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN); + SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN | + SIRFUART_AFC_CTRL_RX_THD); if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) @@ -417,7 +402,7 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count) if (!tty) return -ENODEV; while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) & - ufifo_st->ff_empty(port->line))) { + ufifo_st->ff_empty(port))) { ch = rd_regl(port, ureg->sirfsoc_rx_fifo_data) | SIRFUART_DUMMY_READ; if (unlikely(uart_handle_sysrq_char(port, ch))) @@ -428,7 +413,6 @@ sirfsoc_uart_pio_rx_chars(struct uart_port *port, unsigned int max_rx_count) break; } - sirfport->rx_io_count += rx_count; port->icount.rx += rx_count; return rx_count; @@ -444,7 +428,7 @@ sirfsoc_uart_pio_tx_chars(struct sirfsoc_uart_port *sirfport, int count) unsigned int num_tx = 0; while (!uart_circ_empty(xmit) && !(rd_regl(port, ureg->sirfsoc_tx_fifo_status) & - ufifo_st->ff_full(port->line)) && + ufifo_st->ff_full(port)) && count--) { wr_regl(port, ureg->sirfsoc_tx_fifo_data, xmit->buf[xmit->tail]); @@ -478,139 +462,6 @@ static void sirfsoc_uart_tx_dma_complete_callback(void *param) spin_unlock_irqrestore(&port->lock, flags); } -static void sirfsoc_uart_insert_rx_buf_to_tty( - struct sirfsoc_uart_port *sirfport, int count) -{ - struct uart_port *port = &sirfport->port; - struct tty_port *tport = &port->state->port; - int inserted; - - inserted = tty_insert_flip_string(tport, - sirfport->rx_dma_items[sirfport->rx_completed].xmit.buf, count); - port->icount.rx += inserted; -} - -static void sirfsoc_rx_submit_one_dma_desc(struct uart_port *port, int index) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - - sirfport->rx_dma_items[index].xmit.tail = - sirfport->rx_dma_items[index].xmit.head = 0; - sirfport->rx_dma_items[index].desc = - dmaengine_prep_slave_single(sirfport->rx_dma_chan, - sirfport->rx_dma_items[index].dma_addr, SIRFSOC_RX_DMA_BUF_SIZE, - DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); - if (!sirfport->rx_dma_items[index].desc) { - dev_err(port->dev, "DMA slave single fail\n"); - return; - } - sirfport->rx_dma_items[index].desc->callback = - sirfsoc_uart_rx_dma_complete_callback; - sirfport->rx_dma_items[index].desc->callback_param = sirfport; - sirfport->rx_dma_items[index].cookie = - dmaengine_submit(sirfport->rx_dma_items[index].desc); - dma_async_issue_pending(sirfport->rx_dma_chan); -} - -static void sirfsoc_rx_tmo_process_tl(unsigned long param) -{ - struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param; - struct uart_port *port = &sirfport->port; - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st; - unsigned int count; - unsigned long flags; - struct dma_tx_state tx_state; - - spin_lock_irqsave(&port->lock, flags); - while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan, - sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) { - sirfsoc_uart_insert_rx_buf_to_tty(sirfport, - SIRFSOC_RX_DMA_BUF_SIZE); - sirfport->rx_completed++; - sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT; - } - count = CIRC_CNT(sirfport->rx_dma_items[sirfport->rx_issued].xmit.head, - sirfport->rx_dma_items[sirfport->rx_issued].xmit.tail, - SIRFSOC_RX_DMA_BUF_SIZE); - if (count > 0) - sirfsoc_uart_insert_rx_buf_to_tty(sirfport, count); - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, - rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | - SIRFUART_IO_MODE); - sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count); - if (sirfport->rx_io_count == 4) { - sirfport->rx_io_count = 0; - wr_regl(port, ureg->sirfsoc_int_st_reg, - uint_st->sirfsoc_rx_done); - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) & - ~(uint_en->sirfsoc_rx_done_en)); - else - wr_regl(port, SIRFUART_INT_EN_CLR, - uint_en->sirfsoc_rx_done_en); - sirfsoc_uart_start_next_rx_dma(port); - } else { - wr_regl(port, ureg->sirfsoc_int_st_reg, - uint_st->sirfsoc_rx_done); - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) | - (uint_en->sirfsoc_rx_done_en)); - else - wr_regl(port, ureg->sirfsoc_int_en_reg, - uint_en->sirfsoc_rx_done_en); - } - spin_unlock_irqrestore(&port->lock, flags); - tty_flip_buffer_push(&port->state->port); -} - -static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport) -{ - struct uart_port *port = &sirfport->port; - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - struct dma_tx_state tx_state; - dmaengine_tx_status(sirfport->rx_dma_chan, - sirfport->rx_dma_items[sirfport->rx_issued].cookie, &tx_state); - dmaengine_terminate_all(sirfport->rx_dma_chan); - sirfport->rx_dma_items[sirfport->rx_issued].xmit.head = - SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue; - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) & - ~(uint_en->sirfsoc_rx_timeout_en)); - else - wr_regl(port, SIRFUART_INT_EN_CLR, - uint_en->sirfsoc_rx_timeout_en); - tasklet_schedule(&sirfport->rx_tmo_process_tasklet); -} - -static void sirfsoc_uart_handle_rx_done(struct sirfsoc_uart_port *sirfport) -{ - struct uart_port *port = &sirfport->port; - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - struct sirfsoc_int_status *uint_st = &sirfport->uart_reg->uart_int_st; - - sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count); - if (sirfport->rx_io_count == 4) { - sirfport->rx_io_count = 0; - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) & - ~(uint_en->sirfsoc_rx_done_en)); - else - wr_regl(port, SIRFUART_INT_EN_CLR, - uint_en->sirfsoc_rx_done_en); - wr_regl(port, ureg->sirfsoc_int_st_reg, - uint_st->sirfsoc_rx_timeout); - sirfsoc_uart_start_next_rx_dma(port); - } -} - static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id) { unsigned long intr_status; @@ -628,20 +479,25 @@ static irqreturn_t sirfsoc_uart_isr(int irq, void *dev_id) intr_status = rd_regl(port, ureg->sirfsoc_int_st_reg); wr_regl(port, ureg->sirfsoc_int_st_reg, intr_status); intr_status &= rd_regl(port, ureg->sirfsoc_int_en_reg); - if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(port, uint_st)))) { + if (unlikely(intr_status & (SIRFUART_ERR_INT_STAT(uint_st, + sirfport->uart_reg->uart_type)))) { if (intr_status & uint_st->sirfsoc_rxd_brk) { port->icount.brk++; if (uart_handle_break(port)) goto recv_char; } - if (intr_status & uint_st->sirfsoc_rx_oflow) + if (intr_status & uint_st->sirfsoc_rx_oflow) { port->icount.overrun++; + flag = TTY_OVERRUN; + } if (intr_status & uint_st->sirfsoc_frm_err) { port->icount.frame++; flag = TTY_FRAME; } - if (intr_status & uint_st->sirfsoc_parity_err) + if (intr_status & uint_st->sirfsoc_parity_err) { + port->icount.parity++; flag = TTY_PARITY; + } wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET); wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); @@ -662,15 +518,51 @@ recv_char: uart_handle_cts_change(port, cts_status); wake_up_interruptible(&state->port.delta_msr_wait); } - if (sirfport->rx_dma_chan) { - if (intr_status & uint_st->sirfsoc_rx_timeout) - sirfsoc_uart_handle_rx_tmo(sirfport); - if (intr_status & uint_st->sirfsoc_rx_done) - sirfsoc_uart_handle_rx_done(sirfport); - } else { - if (intr_status & SIRFUART_RX_IO_INT_ST(uint_st)) - sirfsoc_uart_pio_rx_chars(port, - SIRFSOC_UART_IO_RX_MAX_CNT); + if (!sirfport->rx_dma_chan && + (intr_status & SIRFUART_RX_IO_INT_ST(uint_st))) { + /* + * chip will trigger continuous RX_TIMEOUT interrupt + * in RXFIFO empty and not trigger if RXFIFO recevice + * data in limit time, original method use RX_TIMEOUT + * will trigger lots of useless interrupt in RXFIFO + * empty.RXFIFO received one byte will trigger RX_DONE + * interrupt.use RX_DONE to wait for data received + * into RXFIFO, use RX_THD/RX_FULL for lots data receive + * and use RX_TIMEOUT for the last left data. + */ + if (intr_status & uint_st->sirfsoc_rx_done) { + if (!sirfport->is_atlas7) { + wr_regl(port, ureg->sirfsoc_int_en_reg, + rd_regl(port, ureg->sirfsoc_int_en_reg) + & ~(uint_en->sirfsoc_rx_done_en)); + wr_regl(port, ureg->sirfsoc_int_en_reg, + rd_regl(port, ureg->sirfsoc_int_en_reg) + | (uint_en->sirfsoc_rx_timeout_en)); + } else { + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, + uint_en->sirfsoc_rx_done_en); + wr_regl(port, ureg->sirfsoc_int_en_reg, + uint_en->sirfsoc_rx_timeout_en); + } + } else { + if (intr_status & uint_st->sirfsoc_rx_timeout) { + if (!sirfport->is_atlas7) { + wr_regl(port, ureg->sirfsoc_int_en_reg, + rd_regl(port, ureg->sirfsoc_int_en_reg) + & ~(uint_en->sirfsoc_rx_timeout_en)); + wr_regl(port, ureg->sirfsoc_int_en_reg, + rd_regl(port, ureg->sirfsoc_int_en_reg) + | (uint_en->sirfsoc_rx_done_en)); + } else { + wr_regl(port, + ureg->sirfsoc_int_en_clr_reg, + uint_en->sirfsoc_rx_timeout_en); + wr_regl(port, ureg->sirfsoc_int_en_reg, + uint_en->sirfsoc_rx_done_en); + } + } + sirfsoc_uart_pio_rx_chars(port, port->fifosize); + } } spin_unlock(&port->lock); tty_flip_buffer_push(&state->port); @@ -684,10 +576,10 @@ recv_char: return IRQ_HANDLED; } else { sirfsoc_uart_pio_tx_chars(sirfport, - SIRFSOC_UART_IO_TX_REASONABLE_CNT); + port->fifosize); if ((uart_circ_empty(xmit)) && (rd_regl(port, ureg->sirfsoc_tx_fifo_status) & - ufifo_st->ff_empty(port->line))) + ufifo_st->ff_empty(port))) sirfsoc_uart_stop_tx(port); } } @@ -697,41 +589,8 @@ recv_char: return IRQ_HANDLED; } -static void sirfsoc_uart_rx_dma_complete_tl(unsigned long param) -{ - struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param; - struct uart_port *port = &sirfport->port; - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - unsigned long flags; - struct dma_tx_state tx_state; - spin_lock_irqsave(&port->lock, flags); - while (DMA_COMPLETE == dmaengine_tx_status(sirfport->rx_dma_chan, - sirfport->rx_dma_items[sirfport->rx_completed].cookie, &tx_state)) { - sirfsoc_uart_insert_rx_buf_to_tty(sirfport, - SIRFSOC_RX_DMA_BUF_SIZE); - if (rd_regl(port, ureg->sirfsoc_int_en_reg) & - uint_en->sirfsoc_rx_timeout_en) - sirfsoc_rx_submit_one_dma_desc(port, - sirfport->rx_completed++); - else - sirfport->rx_completed++; - sirfport->rx_completed %= SIRFSOC_RX_LOOP_BUF_CNT; - } - spin_unlock_irqrestore(&port->lock, flags); - tty_flip_buffer_push(&port->state->port); -} - static void sirfsoc_uart_rx_dma_complete_callback(void *param) { - struct sirfsoc_uart_port *sirfport = (struct sirfsoc_uart_port *)param; - unsigned long flags; - - spin_lock_irqsave(&sirfport->port.lock, flags); - sirfport->rx_issued++; - sirfport->rx_issued %= SIRFSOC_RX_LOOP_BUF_CNT; - tasklet_schedule(&sirfport->rx_dma_complete_tasklet); - spin_unlock_irqrestore(&sirfport->port.lock, flags); } /* submit rx dma task into dmaengine */ @@ -740,44 +599,35 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port) struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - int i; - sirfport->rx_io_count = 0; wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & ~SIRFUART_IO_MODE); - for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) - sirfsoc_rx_submit_one_dma_desc(port, i); - sirfport->rx_completed = sirfport->rx_issued = 0; + sirfport->rx_dma_items.xmit.tail = + sirfport->rx_dma_items.xmit.head = 0; + sirfport->rx_dma_items.desc = + dmaengine_prep_dma_cyclic(sirfport->rx_dma_chan, + sirfport->rx_dma_items.dma_addr, SIRFSOC_RX_DMA_BUF_SIZE, + SIRFSOC_RX_DMA_BUF_SIZE / 2, + DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + if (IS_ERR_OR_NULL(sirfport->rx_dma_items.desc)) { + dev_err(port->dev, "DMA slave single fail\n"); + return; + } + sirfport->rx_dma_items.desc->callback = + sirfsoc_uart_rx_dma_complete_callback; + sirfport->rx_dma_items.desc->callback_param = sirfport; + sirfport->rx_dma_items.cookie = + dmaengine_submit(sirfport->rx_dma_items.desc); + dma_async_issue_pending(sirfport->rx_dma_chan); if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, rd_regl(port, ureg->sirfsoc_int_en_reg) | - SIRFUART_RX_DMA_INT_EN(port, uint_en)); + SIRFUART_RX_DMA_INT_EN(uint_en, + sirfport->uart_reg->uart_type)); else wr_regl(port, ureg->sirfsoc_int_en_reg, - SIRFUART_RX_DMA_INT_EN(port, uint_en)); -} - -static void sirfsoc_uart_start_rx(struct uart_port *port) -{ - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; - struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; - - sirfport->rx_io_count = 0; - wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET); - wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); - wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); - if (sirfport->rx_dma_chan) - sirfsoc_uart_start_next_rx_dma(port); - else { - if (!sirfport->is_atlas7) - wr_regl(port, ureg->sirfsoc_int_en_reg, - rd_regl(port, ureg->sirfsoc_int_en_reg) | - SIRFUART_RX_IO_INT_EN(port, uint_en)); - else - wr_regl(port, ureg->sirfsoc_int_en_reg, - SIRFUART_RX_IO_INT_EN(port, uint_en)); - } + SIRFUART_RX_DMA_INT_EN(uint_en, + sirfport->uart_reg->uart_type)); } static unsigned int @@ -789,7 +639,7 @@ sirfsoc_usp_calc_sample_div(unsigned long set_rate, unsigned long ioclk_div = 0; unsigned long temp_delta; - for (sample_div = SIRF_MIN_SAMPLE_DIV; + for (sample_div = SIRF_USP_MIN_SAMPLE_DIV; sample_div <= SIRF_MAX_SAMPLE_DIV; sample_div++) { temp_delta = ioclk_rate - (ioclk_rate + (set_rate * sample_div) / 2) @@ -910,10 +760,11 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, config_reg |= SIRFUART_STICK_BIT_MARK; else config_reg |= SIRFUART_STICK_BIT_SPACE; - } else if (termios->c_cflag & PARODD) { - config_reg |= SIRFUART_STICK_BIT_ODD; } else { - config_reg |= SIRFUART_STICK_BIT_EVEN; + if (termios->c_cflag & PARODD) + config_reg |= SIRFUART_STICK_BIT_ODD; + else + config_reg |= SIRFUART_STICK_BIT_EVEN; } } } else { @@ -972,11 +823,10 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, rx_time_out = SIRFSOC_UART_RX_TIMEOUT(set_baud, 20000); rx_time_out = SIRFUART_RECV_TIMEOUT_VALUE(rx_time_out); txfifo_op_reg = rd_regl(port, ureg->sirfsoc_tx_fifo_op); - wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_STOP); wr_regl(port, ureg->sirfsoc_tx_fifo_op, (txfifo_op_reg & ~SIRFUART_FIFO_START)); if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) { - config_reg |= SIRFUART_RECV_TIMEOUT(port, rx_time_out); + config_reg |= SIRFUART_UART_RECV_TIMEOUT(rx_time_out); wr_regl(port, ureg->sirfsoc_line_ctrl, config_reg); } else { /*tx frame ctrl*/ @@ -999,7 +849,7 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, wr_regl(port, ureg->sirfsoc_rx_frame_ctrl, len_val); /*async param*/ wr_regl(port, ureg->sirfsoc_async_param_reg, - (SIRFUART_RECV_TIMEOUT(port, rx_time_out)) | + (SIRFUART_USP_RECV_TIMEOUT(rx_time_out)) | (sample_div_reg & SIRFSOC_USP_ASYNC_DIV2_MASK) << SIRFSOC_USP_ASYNC_DIV2_OFFSET); } @@ -1008,9 +858,14 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, else wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, SIRFUART_IO_MODE); if (sirfport->rx_dma_chan) - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_DMA_MODE); + wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, + rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & + ~SIRFUART_IO_MODE); else - wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, SIRFUART_IO_MODE); + wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, + rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | + SIRFUART_IO_MODE); + sirfport->rx_period_time = 20000000; /* Reset Rx/Tx FIFO Threshold level for proper baudrate */ if (set_baud < 1000000) threshold_div = 1; @@ -1023,7 +878,6 @@ static void sirfsoc_uart_set_termios(struct uart_port *port, txfifo_op_reg |= SIRFUART_FIFO_START; wr_regl(port, ureg->sirfsoc_tx_fifo_op, txfifo_op_reg); uart_update_timeout(port, termios->c_cflag, set_baud); - sirfsoc_uart_start_rx(port); wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_TX_EN | SIRFUART_RX_EN); spin_unlock_irqrestore(&port->lock, flags); } @@ -1032,28 +886,20 @@ static void sirfsoc_uart_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); - if (!state) { - if (sirfport->is_bt_uart) { - clk_prepare_enable(sirfport->clk_noc); - clk_prepare_enable(sirfport->clk_general); - } + if (!state) clk_prepare_enable(sirfport->clk); - } else { + else clk_disable_unprepare(sirfport->clk); - if (sirfport->is_bt_uart) { - clk_disable_unprepare(sirfport->clk_general); - clk_disable_unprepare(sirfport->clk_noc); - } - } } static int sirfsoc_uart_startup(struct uart_port *port) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; + struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en; unsigned int index = port->line; int ret; - set_irq_flags(port->irq, IRQF_VALID | IRQF_NOAUTOEN); + irq_modify_status(port->irq, IRQ_NOREQUEST, IRQ_NOAUTOEN); ret = request_irq(port->irq, sirfsoc_uart_isr, 0, @@ -1064,7 +910,6 @@ static int sirfsoc_uart_startup(struct uart_port *port) index, port->irq); goto irq_err; } - /* initial hardware settings */ wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl) | @@ -1072,6 +917,9 @@ static int sirfsoc_uart_startup(struct uart_port *port) wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | SIRFUART_IO_MODE); + wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, + rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & + ~SIRFUART_RX_DMA_FLUSH); wr_regl(port, ureg->sirfsoc_tx_dma_io_len, 0); wr_regl(port, ureg->sirfsoc_rx_dma_io_len, 0); wr_regl(port, ureg->sirfsoc_tx_rx_en, SIRFUART_RX_EN | SIRFUART_TX_EN); @@ -1080,16 +928,15 @@ static int sirfsoc_uart_startup(struct uart_port *port) SIRFSOC_USP_ENDIAN_CTRL_LSBF | SIRFSOC_USP_EN); wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_RESET); - wr_regl(port, ureg->sirfsoc_tx_fifo_op, 0); wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_RESET); wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0); wr_regl(port, ureg->sirfsoc_tx_fifo_ctrl, SIRFUART_FIFO_THD(port)); wr_regl(port, ureg->sirfsoc_rx_fifo_ctrl, SIRFUART_FIFO_THD(port)); if (sirfport->rx_dma_chan) wr_regl(port, ureg->sirfsoc_rx_fifo_level_chk, - SIRFUART_RX_FIFO_CHK_SC(port->line, 0x4) | - SIRFUART_RX_FIFO_CHK_LC(port->line, 0xe) | - SIRFUART_RX_FIFO_CHK_HC(port->line, 0x1b)); + SIRFUART_RX_FIFO_CHK_SC(port->line, 0x1) | + SIRFUART_RX_FIFO_CHK_LC(port->line, 0x2) | + SIRFUART_RX_FIFO_CHK_HC(port->line, 0x4)); if (sirfport->tx_dma_chan) { sirfport->tx_dma_state = TX_DMA_IDLE; wr_regl(port, ureg->sirfsoc_tx_fifo_level_chk, @@ -1100,8 +947,8 @@ static int sirfsoc_uart_startup(struct uart_port *port) sirfport->ms_enabled = false; if (sirfport->uart_reg->uart_type == SIRF_USP_UART && sirfport->hw_flow_ctrl) { - set_irq_flags(gpio_to_irq(sirfport->cts_gpio), - IRQF_VALID | IRQF_NOAUTOEN); + irq_modify_status(gpio_to_irq(sirfport->cts_gpio), + IRQ_NOREQUEST, IRQ_NOAUTOEN); ret = request_irq(gpio_to_irq(sirfport->cts_gpio), sirfsoc_uart_usp_cts_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "usp_cts_irq", sirfport); @@ -1110,7 +957,40 @@ static int sirfsoc_uart_startup(struct uart_port *port) goto init_rx_err; } } - + if (sirfport->uart_reg->uart_type == SIRF_REAL_UART && + sirfport->rx_dma_chan) + wr_regl(port, ureg->sirfsoc_swh_dma_io, + SIRFUART_CLEAR_RX_ADDR_EN); + if (sirfport->uart_reg->uart_type == SIRF_USP_UART && + sirfport->rx_dma_chan) + wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, + rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | + SIRFSOC_USP_FRADDR_CLR_EN); + if (sirfport->rx_dma_chan && !sirfport->is_hrt_enabled) { + sirfport->is_hrt_enabled = true; + sirfport->rx_period_time = 20000000; + sirfport->rx_last_pos = -1; + sirfport->pio_fetch_cnt = 0; + sirfport->rx_dma_items.xmit.tail = + sirfport->rx_dma_items.xmit.head = 0; + hrtimer_start(&sirfport->hrt, + ns_to_ktime(sirfport->rx_period_time), + HRTIMER_MODE_REL); + } + wr_regl(port, ureg->sirfsoc_rx_fifo_op, SIRFUART_FIFO_START); + if (sirfport->rx_dma_chan) + sirfsoc_uart_start_next_rx_dma(port); + else { + if (!sirfport->is_atlas7) + wr_regl(port, ureg->sirfsoc_int_en_reg, + rd_regl(port, ureg->sirfsoc_int_en_reg) | + SIRFUART_RX_IO_INT_EN(uint_en, + sirfport->uart_reg->uart_type)); + else + wr_regl(port, ureg->sirfsoc_int_en_reg, + SIRFUART_RX_IO_INT_EN(uint_en, + sirfport->uart_reg->uart_type)); + } enable_irq(port->irq); return 0; @@ -1124,10 +1004,13 @@ static void sirfsoc_uart_shutdown(struct uart_port *port) { struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; + struct circ_buf *xmit; + + xmit = &sirfport->rx_dma_items.xmit; if (!sirfport->is_atlas7) wr_regl(port, ureg->sirfsoc_int_en_reg, 0); else - wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL); + wr_regl(port, ureg->sirfsoc_int_en_clr_reg, ~0UL); free_irq(port->irq, sirfport); if (sirfport->ms_enabled) @@ -1139,6 +1022,15 @@ static void sirfsoc_uart_shutdown(struct uart_port *port) } if (sirfport->tx_dma_chan) sirfport->tx_dma_state = TX_DMA_IDLE; + if (sirfport->rx_dma_chan && sirfport->is_hrt_enabled) { + while (((rd_regl(port, ureg->sirfsoc_rx_fifo_status) & + SIRFUART_RX_FIFO_MASK) > sirfport->pio_fetch_cnt) && + !CIRC_CNT(xmit->head, xmit->tail, + SIRFSOC_RX_DMA_BUF_SIZE)) + ; + sirfport->is_hrt_enabled = false; + hrtimer_cancel(&sirfport->hrt); + } } static const char *sirfsoc_uart_type(struct uart_port *port) @@ -1196,27 +1088,29 @@ sirfsoc_uart_console_setup(struct console *co, char *options) unsigned int bits = 8; unsigned int parity = 'n'; unsigned int flow = 'n'; - struct uart_port *port = &sirfsoc_uart_ports[co->index].port; - struct sirfsoc_uart_port *sirfport = to_sirfport(port); - struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; + struct sirfsoc_uart_port *sirfport; + struct sirfsoc_register *ureg; if (co->index < 0 || co->index >= SIRFSOC_UART_NR) - return -EINVAL; - - if (!port->mapbase) + co->index = 1; + sirfport = sirf_ports[co->index]; + if (!sirfport) + return -ENODEV; + ureg = &sirfport->uart_reg->uart_reg; + if (!sirfport->port.mapbase) return -ENODEV; /* enable usp in mode1 register */ if (sirfport->uart_reg->uart_type == SIRF_USP_UART) - wr_regl(port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN | + wr_regl(&sirfport->port, ureg->sirfsoc_mode1, SIRFSOC_USP_EN | SIRFSOC_USP_ENDIAN_CTRL_LSBF); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); - port->cons = co; + sirfport->port.cons = co; /* default console tx/rx transfer using io mode */ sirfport->rx_dma_chan = NULL; sirfport->tx_dma_chan = NULL; - return uart_set_options(port, co, baud, parity, bits, flow); + return uart_set_options(&sirfport->port, co, baud, parity, bits, flow); } static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch) @@ -1224,8 +1118,8 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch) struct sirfsoc_uart_port *sirfport = to_sirfport(port); struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg; struct sirfsoc_fifo_status *ufifo_st = &sirfport->uart_reg->fifo_status; - while (rd_regl(port, - ureg->sirfsoc_tx_fifo_status) & ufifo_st->ff_full(port->line)) + while (rd_regl(port, ureg->sirfsoc_tx_fifo_status) & + ufifo_st->ff_full(port)) cpu_relax(); wr_regl(port, ureg->sirfsoc_tx_fifo_data, ch); } @@ -1233,8 +1127,10 @@ static void sirfsoc_uart_console_putchar(struct uart_port *port, int ch) static void sirfsoc_uart_console_write(struct console *co, const char *s, unsigned int count) { - struct uart_port *port = &sirfsoc_uart_ports[co->index].port; - uart_console_write(port, s, count, sirfsoc_uart_console_putchar); + struct sirfsoc_uart_port *sirfport = sirf_ports[co->index]; + + uart_console_write(&sirfport->port, s, count, + sirfsoc_uart_console_putchar); } static struct console sirfsoc_uart_console = { @@ -1269,10 +1165,99 @@ static struct uart_driver sirfsoc_uart_drv = { #endif }; -static const struct of_device_id sirfsoc_uart_ids[] = { +static enum hrtimer_restart + sirfsoc_uart_rx_dma_hrtimer_callback(struct hrtimer *hrt) +{ + struct sirfsoc_uart_port *sirfport; + struct uart_port *port; + int count, inserted; + struct dma_tx_state tx_state; + struct tty_struct *tty; + struct sirfsoc_register *ureg; + struct circ_buf *xmit; + struct sirfsoc_fifo_status *ufifo_st; + int max_pio_cnt; + + sirfport = container_of(hrt, struct sirfsoc_uart_port, hrt); + port = &sirfport->port; + inserted = 0; + tty = port->state->port.tty; + ureg = &sirfport->uart_reg->uart_reg; + xmit = &sirfport->rx_dma_items.xmit; + ufifo_st = &sirfport->uart_reg->fifo_status; + + dmaengine_tx_status(sirfport->rx_dma_chan, + sirfport->rx_dma_items.cookie, &tx_state); + if (SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue != + sirfport->rx_last_pos) { + xmit->head = SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue; + sirfport->rx_last_pos = xmit->head; + sirfport->pio_fetch_cnt = 0; + } + count = CIRC_CNT_TO_END(xmit->head, xmit->tail, + SIRFSOC_RX_DMA_BUF_SIZE); + while (count > 0) { + inserted = tty_insert_flip_string(tty->port, + (const unsigned char *)&xmit->buf[xmit->tail], count); + if (!inserted) + goto next_hrt; + port->icount.rx += inserted; + xmit->tail = (xmit->tail + inserted) & + (SIRFSOC_RX_DMA_BUF_SIZE - 1); + count = CIRC_CNT_TO_END(xmit->head, xmit->tail, + SIRFSOC_RX_DMA_BUF_SIZE); + tty_flip_buffer_push(tty->port); + } + /* + * if RX DMA buffer data have all push into tty buffer, and there is + * only little data(less than a dma transfer unit) left in rxfifo, + * fetch it out in pio mode and switch back to dma immediately + */ + if (!inserted && !count && + ((rd_regl(port, ureg->sirfsoc_rx_fifo_status) & + SIRFUART_RX_FIFO_MASK) > sirfport->pio_fetch_cnt)) { + dmaengine_pause(sirfport->rx_dma_chan); + /* switch to pio mode */ + wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, + rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | + SIRFUART_IO_MODE); + /* + * UART controller SWH_DMA_IO register have CLEAR_RX_ADDR_EN + * When found changing I/O to DMA mode, it clears + * two low bits of read point; + * USP have similar FRADDR_CLR_EN bit in USP_RX_DMA_IO_CTRL. + * Fetch data out from rxfifo into DMA buffer in PIO mode, + * while switch back to DMA mode, the data fetched will override + * by DMA, as hardware have a strange behaviour: + * after switch back to DMA mode, check rxfifo status it will + * be the number PIO fetched, so record the fetched data count + * to avoid the repeated fetch + */ + max_pio_cnt = 3; + while (!(rd_regl(port, ureg->sirfsoc_rx_fifo_status) & + ufifo_st->ff_empty(port)) && max_pio_cnt--) { + xmit->buf[xmit->head] = + rd_regl(port, ureg->sirfsoc_rx_fifo_data); + xmit->head = (xmit->head + 1) & + (SIRFSOC_RX_DMA_BUF_SIZE - 1); + sirfport->pio_fetch_cnt++; + } + /* switch back to dma mode */ + wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, + rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) & + ~SIRFUART_IO_MODE); + dmaengine_resume(sirfport->rx_dma_chan); + } +next_hrt: + hrtimer_forward_now(hrt, ns_to_ktime(sirfport->rx_period_time)); + return HRTIMER_RESTART; +} + +static struct of_device_id sirfsoc_uart_ids[] = { { .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,}, { .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart}, { .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp}, + { .compatible = "sirf,atlas7-usp-uart", .data = &sirfsoc_usp}, {} }; MODULE_DEVICE_TABLE(of, sirfsoc_uart_ids); @@ -1283,9 +1268,8 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) struct uart_port *port; struct resource *res; int ret; - int i, j; struct dma_slave_config slv_cfg = { - .src_maxburst = 2, + .src_maxburst = 1, }; struct dma_slave_config tx_slv_cfg = { .dst_maxburst = 2, @@ -1293,16 +1277,15 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) const struct of_device_id *match; match = of_match_node(sirfsoc_uart_ids, pdev->dev.of_node); - if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) { - dev_err(&pdev->dev, - "Unable to find cell-index in uart node.\n"); - ret = -EFAULT; + sirfport = devm_kzalloc(&pdev->dev, sizeof(*sirfport), GFP_KERNEL); + if (!sirfport) { + ret = -ENOMEM; goto err; } - if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) - pdev->id += ((struct sirfsoc_uart_register *) - match->data)->uart_param.register_uart_nr; - sirfport = &sirfsoc_uart_ports[pdev->id]; + sirfport->port.line = of_alias_get_id(pdev->dev.of_node, "serial"); + sirf_ports[sirfport->port.line] = sirfport; + sirfport->port.iotype = UPIO_MEM; + sirfport->port.flags = UPF_BOOT_AUTOCONF; port = &sirfport->port; port->dev = &pdev->dev; port->private_data = sirfport; @@ -1310,9 +1293,12 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) sirfport->hw_flow_ctrl = of_property_read_bool(pdev->dev.of_node, "sirf,uart-has-rtscts"); - if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart")) + if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-uart") || + of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart")) sirfport->uart_reg->uart_type = SIRF_REAL_UART; - if (of_device_is_compatible(pdev->dev.of_node, "sirf,prima2-usp-uart")) { + if (of_device_is_compatible(pdev->dev.of_node, + "sirf,prima2-usp-uart") || of_device_is_compatible( + pdev->dev.of_node, "sirf,atlas7-usp-uart")) { sirfport->uart_reg->uart_type = SIRF_USP_UART; if (!sirfport->hw_flow_ctrl) goto usp_no_flow_control; @@ -1350,7 +1336,8 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) gpio_direction_output(sirfport->rts_gpio, 1); } usp_no_flow_control: - if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart")) + if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart") || + of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-usp-uart")) sirfport->is_atlas7 = true; if (of_property_read_u32(pdev->dev.of_node, @@ -1368,12 +1355,9 @@ usp_no_flow_control: ret = -EFAULT; goto err; } - tasklet_init(&sirfport->rx_dma_complete_tasklet, - sirfsoc_uart_rx_dma_complete_tl, (unsigned long)sirfport); - tasklet_init(&sirfport->rx_tmo_process_tasklet, - sirfsoc_rx_tmo_process_tl, (unsigned long)sirfport); port->mapbase = res->start; - port->membase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + port->membase = devm_ioremap(&pdev->dev, + res->start, resource_size(res)); if (!port->membase) { dev_err(&pdev->dev, "Cannot remap resource.\n"); ret = -ENOMEM; @@ -1393,20 +1377,6 @@ usp_no_flow_control: goto err; } port->uartclk = clk_get_rate(sirfport->clk); - if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-bt-uart")) { - sirfport->clk_general = devm_clk_get(&pdev->dev, "general"); - if (IS_ERR(sirfport->clk_general)) { - ret = PTR_ERR(sirfport->clk_general); - goto err; - } - sirfport->clk_noc = devm_clk_get(&pdev->dev, "noc"); - if (IS_ERR(sirfport->clk_noc)) { - ret = PTR_ERR(sirfport->clk_noc); - goto err; - } - sirfport->is_bt_uart = true; - } else - sirfport->is_bt_uart = false; port->ops = &sirfsoc_uart_ops; spin_lock_init(&port->lock); @@ -1419,30 +1389,32 @@ usp_no_flow_control: } sirfport->rx_dma_chan = dma_request_slave_channel(port->dev, "rx"); - for (i = 0; sirfport->rx_dma_chan && i < SIRFSOC_RX_LOOP_BUF_CNT; i++) { - sirfport->rx_dma_items[i].xmit.buf = - dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - &sirfport->rx_dma_items[i].dma_addr, GFP_KERNEL); - if (!sirfport->rx_dma_items[i].xmit.buf) { - dev_err(port->dev, "Uart alloc bufa failed\n"); - ret = -ENOMEM; - goto alloc_coherent_err; - } - sirfport->rx_dma_items[i].xmit.head = - sirfport->rx_dma_items[i].xmit.tail = 0; + sirfport->rx_dma_items.xmit.buf = + dma_alloc_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, + &sirfport->rx_dma_items.dma_addr, GFP_KERNEL); + if (!sirfport->rx_dma_items.xmit.buf) { + dev_err(port->dev, "Uart alloc bufa failed\n"); + ret = -ENOMEM; + goto alloc_coherent_err; } + sirfport->rx_dma_items.xmit.head = + sirfport->rx_dma_items.xmit.tail = 0; if (sirfport->rx_dma_chan) dmaengine_slave_config(sirfport->rx_dma_chan, &slv_cfg); sirfport->tx_dma_chan = dma_request_slave_channel(port->dev, "tx"); if (sirfport->tx_dma_chan) dmaengine_slave_config(sirfport->tx_dma_chan, &tx_slv_cfg); + if (sirfport->rx_dma_chan) { + hrtimer_init(&sirfport->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + sirfport->hrt.function = sirfsoc_uart_rx_dma_hrtimer_callback; + sirfport->is_hrt_enabled = false; + } return 0; alloc_coherent_err: - for (j = 0; j < i; j++) - dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - sirfport->rx_dma_items[j].xmit.buf, - sirfport->rx_dma_items[j].dma_addr); + dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, + sirfport->rx_dma_items.xmit.buf, + sirfport->rx_dma_items.dma_addr); dma_release_channel(sirfport->rx_dma_chan); err: return ret; @@ -1454,13 +1426,11 @@ static int sirfsoc_uart_remove(struct platform_device *pdev) struct uart_port *port = &sirfport->port; uart_remove_one_port(&sirfsoc_uart_drv, port); if (sirfport->rx_dma_chan) { - int i; dmaengine_terminate_all(sirfport->rx_dma_chan); dma_release_channel(sirfport->rx_dma_chan); - for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++) - dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, - sirfport->rx_dma_items[i].xmit.buf, - sirfport->rx_dma_items[i].dma_addr); + dma_free_coherent(port->dev, SIRFSOC_RX_DMA_BUF_SIZE, + sirfport->rx_dma_items.xmit.buf, + sirfport->rx_dma_items.dma_addr); } if (sirfport->tx_dma_chan) { dmaengine_terminate_all(sirfport->tx_dma_chan); diff --git a/kernel/drivers/tty/serial/sirfsoc_uart.h b/kernel/drivers/tty/serial/sirfsoc_uart.h index 727eb6b88..c3a885b4d 100644 --- a/kernel/drivers/tty/serial/sirfsoc_uart.h +++ b/kernel/drivers/tty/serial/sirfsoc_uart.h @@ -6,11 +6,11 @@ * Licensed under GPLv2 or later. */ #include <linux/bitops.h> +#include <linux/log2.h> +#include <linux/hrtimer.h> struct sirfsoc_uart_param { const char *uart_name; const char *port_name; - u32 uart_nr; - u32 register_uart_nr; }; struct sirfsoc_register { @@ -21,6 +21,7 @@ struct sirfsoc_register { u32 sirfsoc_tx_rx_en; u32 sirfsoc_int_en_reg; u32 sirfsoc_int_st_reg; + u32 sirfsoc_int_en_clr_reg; u32 sirfsoc_tx_dma_io_ctrl; u32 sirfsoc_tx_dma_io_len; u32 sirfsoc_tx_fifo_ctrl; @@ -45,8 +46,8 @@ struct sirfsoc_register { u32 sirfsoc_async_param_reg; }; -typedef u32 (*fifo_full_mask)(int line); -typedef u32 (*fifo_empty_mask)(int line); +typedef u32 (*fifo_full_mask)(struct uart_port *port); +typedef u32 (*fifo_empty_mask)(struct uart_port *port); struct sirfsoc_fifo_status { fifo_full_mask ff_full; @@ -105,21 +106,20 @@ struct sirfsoc_uart_register { enum sirfsoc_uart_type uart_type; }; -u32 usp_ff_full(int line) +u32 uart_usp_ff_full_mask(struct uart_port *port) { - return 0x80; -} -u32 usp_ff_empty(int line) -{ - return 0x100; -} -u32 uart_ff_full(int line) -{ - return (line == 1) ? (0x20) : (0x80); + u32 full_bit; + + full_bit = ilog2(port->fifosize); + return (1 << full_bit); } -u32 uart_ff_empty(int line) + +u32 uart_usp_ff_empty_mask(struct uart_port *port) { - return (line == 1) ? (0x40) : (0x100); + u32 empty_bit; + + empty_bit = ilog2(port->fifosize) + 1; + return (1 << empty_bit); } struct sirfsoc_uart_register sirfsoc_usp = { .uart_reg = { @@ -145,6 +145,7 @@ struct sirfsoc_uart_register sirfsoc_usp = { .sirfsoc_rx_fifo_op = 0x0130, .sirfsoc_rx_fifo_status = 0x0134, .sirfsoc_rx_fifo_data = 0x0138, + .sirfsoc_int_en_clr_reg = 0x140, }, .uart_int_en = { .sirfsoc_rx_done_en = BIT(0), @@ -177,14 +178,12 @@ struct sirfsoc_uart_register sirfsoc_usp = { .sirfsoc_rxd_brk = BIT(15), }, .fifo_status = { - .ff_full = usp_ff_full, - .ff_empty = usp_ff_empty, + .ff_full = uart_usp_ff_full_mask, + .ff_empty = uart_usp_ff_empty_mask, }, .uart_param = { .uart_name = "ttySiRF", .port_name = "sirfsoc-uart", - .uart_nr = 2, - .register_uart_nr = 3, }, }; @@ -195,6 +194,7 @@ struct sirfsoc_uart_register sirfsoc_uart = { .sirfsoc_divisor = 0x0050, .sirfsoc_int_en_reg = 0x0054, .sirfsoc_int_st_reg = 0x0058, + .sirfsoc_int_en_clr_reg = 0x0060, .sirfsoc_tx_dma_io_ctrl = 0x0100, .sirfsoc_tx_dma_io_len = 0x0104, .sirfsoc_tx_fifo_ctrl = 0x0108, @@ -249,14 +249,12 @@ struct sirfsoc_uart_register sirfsoc_uart = { .sirfsoc_rts = BIT(15), }, .fifo_status = { - .ff_full = uart_ff_full, - .ff_empty = uart_ff_empty, + .ff_full = uart_usp_ff_full_mask, + .ff_empty = uart_usp_ff_empty_mask, }, .uart_param = { .uart_name = "ttySiRF", .port_name = "sirfsoc_uart", - .uart_nr = 3, - .register_uart_nr = 0, }, }; /* uart io ctrl */ @@ -296,10 +294,11 @@ struct sirfsoc_uart_register sirfsoc_uart = { #define SIRFUART_IO_MODE BIT(0) #define SIRFUART_DMA_MODE 0x0 +#define SIRFUART_RX_DMA_FLUSH 0x4 -/* Macro Specific*/ -#define SIRFUART_INT_EN_CLR 0x0060 +#define SIRFUART_CLEAR_RX_ADDR_EN 0x2 /* Baud Rate Calculation */ +#define SIRF_USP_MIN_SAMPLE_DIV 0x1 #define SIRF_MIN_SAMPLE_DIV 0xf #define SIRF_MAX_SAMPLE_DIV 0x3f #define SIRF_IOCLK_DIV_MAX 0xffff @@ -326,55 +325,55 @@ struct sirfsoc_uart_register sirfsoc_uart = { #define SIRFSOC_USP_RX_CLK_DIVISOR_OFFSET 24 #define SIRFSOC_USP_ASYNC_DIV2_MASK 0x3f #define SIRFSOC_USP_ASYNC_DIV2_OFFSET 16 - +#define SIRFSOC_USP_LOOP_BACK_CTRL BIT(2) +#define SIRFSOC_USP_FRADDR_CLR_EN BIT(1) /* USP-UART Common */ #define SIRFSOC_UART_RX_TIMEOUT(br, to) (((br) * (((to) + 999) / 1000)) / 1000) #define SIRFUART_RECV_TIMEOUT_VALUE(x) \ (((x) > 0xFFFF) ? 0xFFFF : ((x) & 0xFFFF)) -#define SIRFUART_RECV_TIMEOUT(port, x) \ - (((port)->line > 2) ? (x & 0xFFFF) : ((x) & 0xFFFF) << 16) +#define SIRFUART_USP_RECV_TIMEOUT(x) (x & 0xFFFF) +#define SIRFUART_UART_RECV_TIMEOUT(x) ((x & 0xFFFF) << 16) -#define SIRFUART_FIFO_THD(port) ((port->line) == 1 ? 16 : 64) -#define SIRFUART_ERR_INT_STAT(port, unit_st) \ +#define SIRFUART_FIFO_THD(port) (port->fifosize >> 1) +#define SIRFUART_ERR_INT_STAT(unit_st, uart_type) \ (uint_st->sirfsoc_rx_oflow | \ uint_st->sirfsoc_frm_err | \ uint_st->sirfsoc_rxd_brk | \ - ((port->line > 2) ? 0 : uint_st->sirfsoc_parity_err)) -#define SIRFUART_RX_IO_INT_EN(port, uint_en) \ - (uint_en->sirfsoc_rx_timeout_en |\ + ((uart_type != SIRF_REAL_UART) ? \ + 0 : uint_st->sirfsoc_parity_err)) +#define SIRFUART_RX_IO_INT_EN(uint_en, uart_type) \ + (uint_en->sirfsoc_rx_done_en |\ uint_en->sirfsoc_rxfifo_thd_en |\ uint_en->sirfsoc_rxfifo_full_en |\ uint_en->sirfsoc_frm_err_en |\ uint_en->sirfsoc_rx_oflow_en |\ uint_en->sirfsoc_rxd_brk_en |\ - ((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en)) + ((uart_type != SIRF_REAL_UART) ? \ + 0 : uint_en->sirfsoc_parity_err_en)) #define SIRFUART_RX_IO_INT_ST(uint_st) \ - (uint_st->sirfsoc_rx_timeout |\ - uint_st->sirfsoc_rxfifo_thd |\ - uint_st->sirfsoc_rxfifo_full) + (uint_st->sirfsoc_rxfifo_thd |\ + uint_st->sirfsoc_rxfifo_full|\ + uint_st->sirfsoc_rx_done |\ + uint_st->sirfsoc_rx_timeout) #define SIRFUART_CTS_INT_ST(uint_st) (uint_st->sirfsoc_cts) -#define SIRFUART_RX_DMA_INT_EN(port, uint_en) \ - (uint_en->sirfsoc_rx_timeout_en |\ - uint_en->sirfsoc_frm_err_en |\ +#define SIRFUART_RX_DMA_INT_EN(uint_en, uart_type) \ + (uint_en->sirfsoc_frm_err_en |\ uint_en->sirfsoc_rx_oflow_en |\ uint_en->sirfsoc_rxd_brk_en |\ - ((port->line > 2) ? 0 : uint_en->sirfsoc_parity_err_en)) + ((uart_type != SIRF_REAL_UART) ? \ + 0 : uint_en->sirfsoc_parity_err_en)) /* Generic Definitions */ #define SIRFSOC_UART_NAME "ttySiRF" #define SIRFSOC_UART_MAJOR 0 #define SIRFSOC_UART_MINOR 0 #define SIRFUART_PORT_NAME "sirfsoc-uart" #define SIRFUART_MAP_SIZE 0x200 -#define SIRFSOC_UART_NR 6 +#define SIRFSOC_UART_NR 11 #define SIRFSOC_PORT_TYPE 0xa5 /* Uart Common Use Macro*/ -#define SIRFSOC_RX_DMA_BUF_SIZE 256 +#define SIRFSOC_RX_DMA_BUF_SIZE (1024 * 32) #define BYTES_TO_ALIGN(dma_addr) ((unsigned long)(dma_addr) & 0x3) -#define LOOP_DMA_BUFA_FILL 1 -#define LOOP_DMA_BUFB_FILL 2 -#define TX_TRAN_PIO 1 -#define TX_TRAN_DMA 2 /* Uart Fifo Level Chk */ #define SIRFUART_TX_FIFO_SC_OFFSET 0 #define SIRFUART_TX_FIFO_LC_OFFSET 10 @@ -389,8 +388,8 @@ struct sirfsoc_uart_register sirfsoc_uart = { #define SIRFUART_RX_FIFO_CHK_SC SIRFUART_TX_FIFO_CHK_SC #define SIRFUART_RX_FIFO_CHK_LC SIRFUART_TX_FIFO_CHK_LC #define SIRFUART_RX_FIFO_CHK_HC SIRFUART_TX_FIFO_CHK_HC +#define SIRFUART_RX_FIFO_MASK 0x7f /* Indicate how many buffers used */ -#define SIRFSOC_RX_LOOP_BUF_CNT 2 /* For Fast Baud Rate Calculation */ struct sirfsoc_baudrate_to_regv { @@ -404,7 +403,7 @@ enum sirfsoc_tx_state { TX_DMA_PAUSE, }; -struct sirfsoc_loop_buffer { +struct sirfsoc_rx_buffer { struct circ_buf xmit; dma_cookie_t cookie; struct dma_async_tx_descriptor *desc; @@ -417,10 +416,6 @@ struct sirfsoc_uart_port { struct uart_port port; struct clk *clk; - /* UART6 for BT usage in A7DA platform need multi-clock source */ - bool is_bt_uart; - struct clk *clk_general; - struct clk *clk_noc; /* for SiRFatlas7, there are SET/CLR for UART_INT_EN */ bool is_atlas7; struct sirfsoc_uart_register *uart_reg; @@ -428,17 +423,17 @@ struct sirfsoc_uart_port { struct dma_chan *tx_dma_chan; dma_addr_t tx_dma_addr; struct dma_async_tx_descriptor *tx_dma_desc; - struct tasklet_struct rx_dma_complete_tasklet; - struct tasklet_struct rx_tmo_process_tasklet; - unsigned int rx_io_count; unsigned long transfer_size; enum sirfsoc_tx_state tx_dma_state; unsigned int cts_gpio; unsigned int rts_gpio; - struct sirfsoc_loop_buffer rx_dma_items[SIRFSOC_RX_LOOP_BUF_CNT]; - int rx_completed; - int rx_issued; + struct sirfsoc_rx_buffer rx_dma_items; + struct hrtimer hrt; + bool is_hrt_enabled; + unsigned long rx_period_time; + unsigned long rx_last_pos; + unsigned long pio_fetch_cnt; }; /* Register Access Control */ @@ -447,10 +442,6 @@ struct sirfsoc_uart_port { #define wr_regl(port, reg, val) __raw_writel(val, portaddr(port, reg)) /* UART Port Mask */ -#define SIRFUART_FIFOLEVEL_MASK(port) ((port->line == 1) ? (0x1f) : (0x7f)) -#define SIRFUART_FIFOFULL_MASK(port) ((port->line == 1) ? (0x20) : (0x80)) -#define SIRFUART_FIFOEMPTY_MASK(port) ((port->line == 1) ? (0x40) : (0x100)) - -/* I/O Mode */ -#define SIRFSOC_UART_IO_RX_MAX_CNT 256 -#define SIRFSOC_UART_IO_TX_REASONABLE_CNT 256 +#define SIRFUART_FIFOLEVEL_MASK(port) ((port->fifosize - 1) & 0xFFF) +#define SIRFUART_FIFOFULL_MASK(port) (port->fifosize & 0xFFF) +#define SIRFUART_FIFOEMPTY_MASK(port) ((port->fifosize & 0xFFF) << 1) diff --git a/kernel/drivers/tty/serial/sn_console.c b/kernel/drivers/tty/serial/sn_console.c index 33e94e56d..d4692d888 100644 --- a/kernel/drivers/tty/serial/sn_console.c +++ b/kernel/drivers/tty/serial/sn_console.c @@ -42,7 +42,7 @@ #include <linux/tty_flip.h> #include <linux/serial.h> #include <linux/console.h> -#include <linux/module.h> +#include <linux/init.h> #include <linux/sysrq.h> #include <linux/circ_buf.h> #include <linux/serial_reg.h> @@ -659,7 +659,7 @@ static void sn_sal_timer_poll(unsigned long data) * @port: Our sn_cons_port (which contains the uart port) * * So this is used by sn_sal_serial_console_init (early on, before we're - * registered with serial core). It's also used by sn_sal_module_init + * registered with serial core). It's also used by sn_sal_init * right after we've registered with serial core. The later only happens * if we didn't already come through here via sn_sal_serial_console_init. * @@ -709,7 +709,7 @@ static void __init sn_sal_switch_to_asynch(struct sn_cons_port *port) * sn_sal_switch_to_interrupts - Switch to interrupt driven mode * @port: Our sn_cons_port (which contains the uart port) * - * In sn_sal_module_init, after we're registered with serial core and + * In sn_sal_init, after we're registered with serial core and * the port is added, this function is called to switch us to interrupt * mode. We were previously in asynch/polling mode (using init_timer). * @@ -773,7 +773,7 @@ static struct uart_driver sal_console_uart = { }; /** - * sn_sal_module_init - When the kernel loads us, get us rolling w/ serial core + * sn_sal_init - When the kernel loads us, get us rolling w/ serial core * * Before this is called, we've been printing kernel messages in a special * early mode not making use of the serial core infrastructure. When our @@ -781,7 +781,7 @@ static struct uart_driver sal_console_uart = { * core and try to enable interrupt driven mode. * */ -static int __init sn_sal_module_init(void) +static int __init sn_sal_init(void) { int retval; @@ -811,7 +811,7 @@ static int __init sn_sal_module_init(void) if (uart_register_driver(&sal_console_uart) < 0) { printk - ("ERROR sn_sal_module_init failed uart_register_driver, line %d\n", + ("ERROR sn_sal_init failed uart_register_driver, line %d\n", __LINE__); return -ENODEV; } @@ -832,33 +832,19 @@ static int __init sn_sal_module_init(void) /* when this driver is compiled in, the console initialization * will have already switched us into asynchronous operation - * before we get here through the module initcalls */ + * before we get here through the initcalls */ if (!sal_console_port.sc_is_asynch) { sn_sal_switch_to_asynch(&sal_console_port); } - /* at this point (module_init) we can try to turn on interrupts */ + /* at this point (device_init) we can try to turn on interrupts */ if (!IS_RUNNING_ON_SIMULATOR()) { sn_sal_switch_to_interrupts(&sal_console_port); } sn_process_input = 1; return 0; } - -/** - * sn_sal_module_exit - When we're unloaded, remove the driver/port - * - */ -static void __exit sn_sal_module_exit(void) -{ - del_timer_sync(&sal_console_port.sc_timer); - uart_remove_one_port(&sal_console_uart, &sal_console_port.sc_port); - uart_unregister_driver(&sal_console_uart); - misc_deregister(&misc); -} - -module_init(sn_sal_module_init); -module_exit(sn_sal_module_exit); +device_initcall(sn_sal_init); /** * puts_raw_fixed - sn_sal_console_write helper for adding \r's as required diff --git a/kernel/drivers/tty/serial/sprd_serial.c b/kernel/drivers/tty/serial/sprd_serial.c index 582d2729f..9dbae01d4 100644 --- a/kernel/drivers/tty/serial/sprd_serial.c +++ b/kernel/drivers/tty/serial/sprd_serial.c @@ -716,7 +716,7 @@ static int sprd_probe(struct platform_device *pdev) up->flags = UPF_BOOT_AUTOCONF; clk = devm_clk_get(&pdev->dev, NULL); - if (!IS_ERR(clk)) + if (!IS_ERR_OR_NULL(clk)) up->uartclk = clk_get_rate(clk); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -782,6 +782,7 @@ static const struct of_device_id serial_ids[] = { {.compatible = "sprd,sc9836-uart",}, {} }; +MODULE_DEVICE_TABLE(of, serial_ids); static struct platform_driver sprd_platform_driver = { .probe = sprd_probe, diff --git a/kernel/drivers/tty/serial/st-asc.c b/kernel/drivers/tty/serial/st-asc.c index d625664ce..2d78cb362 100644 --- a/kernel/drivers/tty/serial/st-asc.c +++ b/kernel/drivers/tty/serial/st-asc.c @@ -430,7 +430,7 @@ static void asc_break_ctl(struct uart_port *port, int break_state) */ static int asc_startup(struct uart_port *port) { - if (request_irq(port->irq, asc_interrupt, IRQF_NO_SUSPEND, + if (request_irq(port->irq, asc_interrupt, 0, asc_port_name(port), port)) { dev_err(port->dev, "cannot allocate irq.\n"); return -ENODEV; diff --git a/kernel/drivers/tty/serial/stm32-usart.c b/kernel/drivers/tty/serial/stm32-usart.c new file mode 100644 index 000000000..f89d1f79b --- /dev/null +++ b/kernel/drivers/tty/serial/stm32-usart.c @@ -0,0 +1,738 @@ +/* + * Copyright (C) Maxime Coquelin 2015 + * Author: Maxime Coquelin <mcoquelin.stm32@gmail.com> + * License terms: GNU General Public License (GPL), version 2 + * + * Inspired by st-asc.c from STMicroelectronics (c) + */ + +#if defined(CONFIG_SERIAL_STM32_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/module.h> +#include <linux/serial.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/serial_core.h> +#include <linux/clk.h> + +#define DRIVER_NAME "stm32-usart" + +/* Register offsets */ +#define USART_SR 0x00 +#define USART_DR 0x04 +#define USART_BRR 0x08 +#define USART_CR1 0x0c +#define USART_CR2 0x10 +#define USART_CR3 0x14 +#define USART_GTPR 0x18 + +/* USART_SR */ +#define USART_SR_PE BIT(0) +#define USART_SR_FE BIT(1) +#define USART_SR_NF BIT(2) +#define USART_SR_ORE BIT(3) +#define USART_SR_IDLE BIT(4) +#define USART_SR_RXNE BIT(5) +#define USART_SR_TC BIT(6) +#define USART_SR_TXE BIT(7) +#define USART_SR_LBD BIT(8) +#define USART_SR_CTS BIT(9) +#define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \ + USART_SR_FE | USART_SR_PE) +/* Dummy bits */ +#define USART_SR_DUMMY_RX BIT(16) + +/* USART_DR */ +#define USART_DR_MASK GENMASK(8, 0) + +/* USART_BRR */ +#define USART_BRR_DIV_F_MASK GENMASK(3, 0) +#define USART_BRR_DIV_M_MASK GENMASK(15, 4) +#define USART_BRR_DIV_M_SHIFT 4 + +/* USART_CR1 */ +#define USART_CR1_SBK BIT(0) +#define USART_CR1_RWU BIT(1) +#define USART_CR1_RE BIT(2) +#define USART_CR1_TE BIT(3) +#define USART_CR1_IDLEIE BIT(4) +#define USART_CR1_RXNEIE BIT(5) +#define USART_CR1_TCIE BIT(6) +#define USART_CR1_TXEIE BIT(7) +#define USART_CR1_PEIE BIT(8) +#define USART_CR1_PS BIT(9) +#define USART_CR1_PCE BIT(10) +#define USART_CR1_WAKE BIT(11) +#define USART_CR1_M BIT(12) +#define USART_CR1_UE BIT(13) +#define USART_CR1_OVER8 BIT(15) +#define USART_CR1_IE_MASK GENMASK(8, 4) + +/* USART_CR2 */ +#define USART_CR2_ADD_MASK GENMASK(3, 0) +#define USART_CR2_LBDL BIT(5) +#define USART_CR2_LBDIE BIT(6) +#define USART_CR2_LBCL BIT(8) +#define USART_CR2_CPHA BIT(9) +#define USART_CR2_CPOL BIT(10) +#define USART_CR2_CLKEN BIT(11) +#define USART_CR2_STOP_2B BIT(13) +#define USART_CR2_STOP_MASK GENMASK(13, 12) +#define USART_CR2_LINEN BIT(14) + +/* USART_CR3 */ +#define USART_CR3_EIE BIT(0) +#define USART_CR3_IREN BIT(1) +#define USART_CR3_IRLP BIT(2) +#define USART_CR3_HDSEL BIT(3) +#define USART_CR3_NACK BIT(4) +#define USART_CR3_SCEN BIT(5) +#define USART_CR3_DMAR BIT(6) +#define USART_CR3_DMAT BIT(7) +#define USART_CR3_RTSE BIT(8) +#define USART_CR3_CTSE BIT(9) +#define USART_CR3_CTSIE BIT(10) +#define USART_CR3_ONEBIT BIT(11) + +/* USART_GTPR */ +#define USART_GTPR_PSC_MASK GENMASK(7, 0) +#define USART_GTPR_GT_MASK GENMASK(15, 8) + +#define DRIVER_NAME "stm32-usart" +#define STM32_SERIAL_NAME "ttyS" +#define STM32_MAX_PORTS 6 + +struct stm32_port { + struct uart_port port; + struct clk *clk; + bool hw_flow_control; +}; + +static struct stm32_port stm32_ports[STM32_MAX_PORTS]; +static struct uart_driver stm32_usart_driver; + +static void stm32_stop_tx(struct uart_port *port); + +static inline struct stm32_port *to_stm32_port(struct uart_port *port) +{ + return container_of(port, struct stm32_port, port); +} + +static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits) +{ + u32 val; + + val = readl_relaxed(port->membase + reg); + val |= bits; + writel_relaxed(val, port->membase + reg); +} + +static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) +{ + u32 val; + + val = readl_relaxed(port->membase + reg); + val &= ~bits; + writel_relaxed(val, port->membase + reg); +} + +static void stm32_receive_chars(struct uart_port *port) +{ + struct tty_port *tport = &port->state->port; + unsigned long c; + u32 sr; + char flag; + + if (port->irq_wake) + pm_wakeup_event(tport->tty->dev, 0); + + while ((sr = readl_relaxed(port->membase + USART_SR)) & USART_SR_RXNE) { + sr |= USART_SR_DUMMY_RX; + c = readl_relaxed(port->membase + USART_DR); + flag = TTY_NORMAL; + port->icount.rx++; + + if (sr & USART_SR_ERR_MASK) { + if (sr & USART_SR_LBD) { + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (sr & USART_SR_ORE) { + port->icount.overrun++; + } else if (sr & USART_SR_PE) { + port->icount.parity++; + } else if (sr & USART_SR_FE) { + port->icount.frame++; + } + + sr &= port->read_status_mask; + + if (sr & USART_SR_LBD) + flag = TTY_BREAK; + else if (sr & USART_SR_PE) + flag = TTY_PARITY; + else if (sr & USART_SR_FE) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, c)) + continue; + uart_insert_char(port, sr, USART_SR_ORE, c, flag); + } + + spin_unlock(&port->lock); + tty_flip_buffer_push(tport); + spin_lock(&port->lock); +} + +static void stm32_transmit_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + + if (port->x_char) { + writel_relaxed(port->x_char, port->membase + USART_DR); + port->x_char = 0; + port->icount.tx++; + return; + } + + if (uart_tx_stopped(port)) { + stm32_stop_tx(port); + return; + } + + if (uart_circ_empty(xmit)) { + stm32_stop_tx(port); + return; + } + + writel_relaxed(xmit->buf[xmit->tail], port->membase + USART_DR); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + stm32_stop_tx(port); +} + +static irqreturn_t stm32_interrupt(int irq, void *ptr) +{ + struct uart_port *port = ptr; + u32 sr; + + spin_lock(&port->lock); + + sr = readl_relaxed(port->membase + USART_SR); + + if (sr & USART_SR_RXNE) + stm32_receive_chars(port); + + if (sr & USART_SR_TXE) + stm32_transmit_chars(port); + + spin_unlock(&port->lock); + + return IRQ_HANDLED; +} + +static unsigned int stm32_tx_empty(struct uart_port *port) +{ + return readl_relaxed(port->membase + USART_SR) & USART_SR_TXE; +} + +static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) + stm32_set_bits(port, USART_CR3, USART_CR3_RTSE); + else + stm32_clr_bits(port, USART_CR3, USART_CR3_RTSE); +} + +static unsigned int stm32_get_mctrl(struct uart_port *port) +{ + /* This routine is used to get signals of: DCD, DSR, RI, and CTS */ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +/* Transmit stop */ +static void stm32_stop_tx(struct uart_port *port) +{ + stm32_clr_bits(port, USART_CR1, USART_CR1_TXEIE); +} + +/* There are probably characters waiting to be transmitted. */ +static void stm32_start_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + + if (uart_circ_empty(xmit)) + return; + + stm32_set_bits(port, USART_CR1, USART_CR1_TXEIE | USART_CR1_TE); +} + +/* Throttle the remote when input buffer is about to overflow. */ +static void stm32_throttle(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE); + spin_unlock_irqrestore(&port->lock, flags); +} + +/* Unthrottle the remote, the input buffer can now accept data. */ +static void stm32_unthrottle(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + stm32_set_bits(port, USART_CR1, USART_CR1_RXNEIE); + spin_unlock_irqrestore(&port->lock, flags); +} + +/* Receive stop */ +static void stm32_stop_rx(struct uart_port *port) +{ + stm32_clr_bits(port, USART_CR1, USART_CR1_RXNEIE); +} + +/* Handle breaks - ignored by us */ +static void stm32_break_ctl(struct uart_port *port, int break_state) +{ +} + +static int stm32_startup(struct uart_port *port) +{ + const char *name = to_platform_device(port->dev)->name; + u32 val; + int ret; + + ret = request_irq(port->irq, stm32_interrupt, 0, name, port); + if (ret) + return ret; + + val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; + stm32_set_bits(port, USART_CR1, val); + + return 0; +} + +static void stm32_shutdown(struct uart_port *port) +{ + u32 val; + + val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; + stm32_set_bits(port, USART_CR1, val); + + free_irq(port->irq, port); +} + +static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + unsigned int baud; + u32 usartdiv, mantissa, fraction, oversampling; + tcflag_t cflag = termios->c_cflag; + u32 cr1, cr2, cr3; + unsigned long flags; + + if (!stm32_port->hw_flow_control) + cflag &= ~CRTSCTS; + + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 8); + + spin_lock_irqsave(&port->lock, flags); + + /* Stop serial port and reset value */ + writel_relaxed(0, port->membase + USART_CR1); + + cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE | USART_CR1_RXNEIE; + cr2 = 0; + cr3 = 0; + + if (cflag & CSTOPB) + cr2 |= USART_CR2_STOP_2B; + + if (cflag & PARENB) { + cr1 |= USART_CR1_PCE; + if ((cflag & CSIZE) == CS8) + cr1 |= USART_CR1_M; + } + + if (cflag & PARODD) + cr1 |= USART_CR1_PS; + + port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); + if (cflag & CRTSCTS) { + port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; + cr3 |= USART_CR3_CTSE; + } + + usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); + + /* + * The USART supports 16 or 8 times oversampling. + * By default we prefer 16 times oversampling, so that the receiver + * has a better tolerance to clock deviations. + * 8 times oversampling is only used to achieve higher speeds. + */ + if (usartdiv < 16) { + oversampling = 8; + stm32_set_bits(port, USART_CR1, USART_CR1_OVER8); + } else { + oversampling = 16; + stm32_clr_bits(port, USART_CR1, USART_CR1_OVER8); + } + + mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; + fraction = usartdiv % oversampling; + writel_relaxed(mantissa | fraction, port->membase + USART_BRR); + + uart_update_timeout(port, cflag, baud); + + port->read_status_mask = USART_SR_ORE; + if (termios->c_iflag & INPCK) + port->read_status_mask |= USART_SR_PE | USART_SR_FE; + if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) + port->read_status_mask |= USART_SR_LBD; + + /* Characters to ignore */ + port->ignore_status_mask = 0; + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask = USART_SR_PE | USART_SR_FE; + if (termios->c_iflag & IGNBRK) { + port->ignore_status_mask |= USART_SR_LBD; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (termios->c_iflag & IGNPAR) + port->ignore_status_mask |= USART_SR_ORE; + } + + /* Ignore all characters if CREAD is not set */ + if ((termios->c_cflag & CREAD) == 0) + port->ignore_status_mask |= USART_SR_DUMMY_RX; + + writel_relaxed(cr3, port->membase + USART_CR3); + writel_relaxed(cr2, port->membase + USART_CR2); + writel_relaxed(cr1, port->membase + USART_CR1); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *stm32_type(struct uart_port *port) +{ + return (port->type == PORT_STM32) ? DRIVER_NAME : NULL; +} + +static void stm32_release_port(struct uart_port *port) +{ +} + +static int stm32_request_port(struct uart_port *port) +{ + return 0; +} + +static void stm32_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_STM32; +} + +static int +stm32_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + /* No user changeable parameters */ + return -EINVAL; +} + +static void stm32_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct stm32_port *stm32port = container_of(port, + struct stm32_port, port); + unsigned long flags = 0; + + switch (state) { + case UART_PM_STATE_ON: + clk_prepare_enable(stm32port->clk); + break; + case UART_PM_STATE_OFF: + spin_lock_irqsave(&port->lock, flags); + stm32_clr_bits(port, USART_CR1, USART_CR1_UE); + spin_unlock_irqrestore(&port->lock, flags); + clk_disable_unprepare(stm32port->clk); + break; + } +} + +static const struct uart_ops stm32_uart_ops = { + .tx_empty = stm32_tx_empty, + .set_mctrl = stm32_set_mctrl, + .get_mctrl = stm32_get_mctrl, + .stop_tx = stm32_stop_tx, + .start_tx = stm32_start_tx, + .throttle = stm32_throttle, + .unthrottle = stm32_unthrottle, + .stop_rx = stm32_stop_rx, + .break_ctl = stm32_break_ctl, + .startup = stm32_startup, + .shutdown = stm32_shutdown, + .set_termios = stm32_set_termios, + .pm = stm32_pm, + .type = stm32_type, + .release_port = stm32_release_port, + .request_port = stm32_request_port, + .config_port = stm32_config_port, + .verify_port = stm32_verify_port, +}; + +static int stm32_init_port(struct stm32_port *stm32port, + struct platform_device *pdev) +{ + struct uart_port *port = &stm32port->port; + struct resource *res; + int ret; + + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + port->ops = &stm32_uart_ops; + port->dev = &pdev->dev; + port->irq = platform_get_irq(pdev, 0); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + port->membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); + port->mapbase = res->start; + + spin_lock_init(&port->lock); + + stm32port->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(stm32port->clk)) + return PTR_ERR(stm32port->clk); + + /* Ensure that clk rate is correct by enabling the clk */ + ret = clk_prepare_enable(stm32port->clk); + if (ret) + return ret; + + stm32port->port.uartclk = clk_get_rate(stm32port->clk); + if (!stm32port->port.uartclk) + ret = -EINVAL; + + clk_disable_unprepare(stm32port->clk); + + return ret; +} + +static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + int id; + + if (!np) + return NULL; + + id = of_alias_get_id(np, "serial"); + if (id < 0) + id = 0; + + if (WARN_ON(id >= STM32_MAX_PORTS)) + return NULL; + + stm32_ports[id].hw_flow_control = of_property_read_bool(np, + "auto-flow-control"); + stm32_ports[id].port.line = id; + return &stm32_ports[id]; +} + +#ifdef CONFIG_OF +static const struct of_device_id stm32_match[] = { + { .compatible = "st,stm32-usart", }, + { .compatible = "st,stm32-uart", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, stm32_match); +#endif + +static int stm32_serial_probe(struct platform_device *pdev) +{ + int ret; + struct stm32_port *stm32port; + + stm32port = stm32_of_get_stm32_port(pdev); + if (!stm32port) + return -ENODEV; + + ret = stm32_init_port(stm32port, pdev); + if (ret) + return ret; + + ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); + if (ret) + return ret; + + platform_set_drvdata(pdev, &stm32port->port); + + return 0; +} + +static int stm32_serial_remove(struct platform_device *pdev) +{ + struct uart_port *port = platform_get_drvdata(pdev); + + return uart_remove_one_port(&stm32_usart_driver, port); +} + + +#ifdef CONFIG_SERIAL_STM32_CONSOLE +static void stm32_console_putchar(struct uart_port *port, int ch) +{ + while (!(readl_relaxed(port->membase + USART_SR) & USART_SR_TXE)) + cpu_relax(); + + writel_relaxed(ch, port->membase + USART_DR); +} + +static void stm32_console_write(struct console *co, const char *s, unsigned cnt) +{ + struct uart_port *port = &stm32_ports[co->index].port; + unsigned long flags; + u32 old_cr1, new_cr1; + int locked = 1; + + local_irq_save(flags); + if (port->sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&port->lock); + else + spin_lock(&port->lock); + + /* Save and disable interrupts */ + old_cr1 = readl_relaxed(port->membase + USART_CR1); + new_cr1 = old_cr1 & ~USART_CR1_IE_MASK; + writel_relaxed(new_cr1, port->membase + USART_CR1); + + uart_console_write(port, s, cnt, stm32_console_putchar); + + /* Restore interrupt state */ + writel_relaxed(old_cr1, port->membase + USART_CR1); + + if (locked) + spin_unlock(&port->lock); + local_irq_restore(flags); +} + +static int stm32_console_setup(struct console *co, char *options) +{ + struct stm32_port *stm32port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= STM32_MAX_PORTS) + return -ENODEV; + + stm32port = &stm32_ports[co->index]; + + /* + * This driver does not support early console initialization + * (use ARM early printk support instead), so we only expect + * this to be called during the uart port registration when the + * driver gets probed and the port should be mapped at that point. + */ + if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL) + return -ENXIO; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&stm32port->port, co, baud, parity, bits, flow); +} + +static struct console stm32_console = { + .name = STM32_SERIAL_NAME, + .device = uart_console_device, + .write = stm32_console_write, + .setup = stm32_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &stm32_usart_driver, +}; + +#define STM32_SERIAL_CONSOLE (&stm32_console) + +#else +#define STM32_SERIAL_CONSOLE NULL +#endif /* CONFIG_SERIAL_STM32_CONSOLE */ + +static struct uart_driver stm32_usart_driver = { + .driver_name = DRIVER_NAME, + .dev_name = STM32_SERIAL_NAME, + .major = 0, + .minor = 0, + .nr = STM32_MAX_PORTS, + .cons = STM32_SERIAL_CONSOLE, +}; + +static struct platform_driver stm32_serial_driver = { + .probe = stm32_serial_probe, + .remove = stm32_serial_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(stm32_match), + }, +}; + +static int __init usart_init(void) +{ + static char banner[] __initdata = "STM32 USART driver initialized"; + int ret; + + pr_info("%s\n", banner); + + ret = uart_register_driver(&stm32_usart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&stm32_serial_driver); + if (ret) + uart_unregister_driver(&stm32_usart_driver); + + return ret; +} + +static void __exit usart_exit(void) +{ + platform_driver_unregister(&stm32_serial_driver); + uart_unregister_driver(&stm32_usart_driver); +} + +module_init(usart_init); +module_exit(usart_exit); + +MODULE_ALIAS("platform:" DRIVER_NAME); +MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver"); +MODULE_LICENSE("GPL v2"); diff --git a/kernel/drivers/tty/serial/suncore.c b/kernel/drivers/tty/serial/suncore.c index 6e4ac8db2..127472bd6 100644 --- a/kernel/drivers/tty/serial/suncore.c +++ b/kernel/drivers/tty/serial/suncore.c @@ -10,7 +10,6 @@ * Copyright (C) 2002 David S. Miller (davem@redhat.com) */ -#include <linux/module.h> #include <linux/kernel.h> #include <linux/console.h> #include <linux/tty.h> @@ -234,14 +233,10 @@ static int __init suncore_init(void) { return 0; } +device_initcall(suncore_init); -static void __exit suncore_exit(void) -{ -} - -module_init(suncore_init); -module_exit(suncore_exit); - +#if 0 /* ..def MODULE ; never supported as such */ MODULE_AUTHOR("Eddie C. Dost, David S. Miller"); MODULE_DESCRIPTION("Sun serial common layer"); MODULE_LICENSE("GPL"); +#endif diff --git a/kernel/drivers/tty/serial/sunhv.c b/kernel/drivers/tty/serial/sunhv.c index 534754440..ca0d3802f 100644 --- a/kernel/drivers/tty/serial/sunhv.c +++ b/kernel/drivers/tty/serial/sunhv.c @@ -3,7 +3,6 @@ * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net) */ -#include <linux/module.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/tty.h> @@ -149,8 +148,10 @@ static int receive_chars_read(struct uart_port *port) uart_handle_dcd_change(port, 1); } - for (i = 0; i < bytes_read; i++) - uart_handle_sysrq_char(port, con_read_page[i]); + if (port->sysrq != 0 && *con_read_page) { + for (i = 0; i < bytes_read; i++) + uart_handle_sysrq_char(port, con_read_page[i]); + } if (port->state == NULL) continue; @@ -169,17 +170,17 @@ struct sunhv_ops { int (*receive_chars)(struct uart_port *port); }; -static struct sunhv_ops bychar_ops = { +static const struct sunhv_ops bychar_ops = { .transmit_chars = transmit_chars_putchar, .receive_chars = receive_chars_getchar, }; -static struct sunhv_ops bywrite_ops = { +static const struct sunhv_ops bywrite_ops = { .transmit_chars = transmit_chars_write, .receive_chars = receive_chars_read, }; -static struct sunhv_ops *sunhv_ops = &bychar_ops; +static const struct sunhv_ops *sunhv_ops = &bychar_ops; static struct tty_port *receive_chars(struct uart_port *port) { @@ -621,7 +622,6 @@ static const struct of_device_id hv_match[] = { }, {}, }; -MODULE_DEVICE_TABLE(of, hv_match); static struct platform_driver hv_driver = { .driver = { @@ -639,16 +639,11 @@ static int __init sunhv_init(void) return platform_driver_register(&hv_driver); } +device_initcall(sunhv_init); -static void __exit sunhv_exit(void) -{ - platform_driver_unregister(&hv_driver); -} - -module_init(sunhv_init); -module_exit(sunhv_exit); - +#if 0 /* ...def MODULE ; never supported as such */ MODULE_AUTHOR("David S. Miller"); MODULE_DESCRIPTION("SUN4V Hypervisor console driver"); MODULE_VERSION("2.0"); MODULE_LICENSE("GPL"); +#endif diff --git a/kernel/drivers/tty/serial/ucc_uart.c b/kernel/drivers/tty/serial/ucc_uart.c index 7d2532b23..73190f5d2 100644 --- a/kernel/drivers/tty/serial/ucc_uart.c +++ b/kernel/drivers/tty/serial/ucc_uart.c @@ -950,7 +950,7 @@ static void qe_uart_set_termios(struct uart_port *port, if ((termios->c_cflag & CREAD) == 0) port->read_status_mask &= ~BD_SC_EMPTY; - baud = uart_get_baud_rate(port, termios, old, 0, 115200); + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); /* Do we really need a spinlock here? */ spin_lock_irqsave(&port->lock, flags); diff --git a/kernel/drivers/tty/serial/xilinx_uartps.c b/kernel/drivers/tty/serial/xilinx_uartps.c index 3ddbac767..009e0dbc1 100644 --- a/kernel/drivers/tty/serial/xilinx_uartps.c +++ b/kernel/drivers/tty/serial/xilinx_uartps.c @@ -1075,7 +1075,8 @@ static void cdns_uart_console_putchar(struct uart_port *port, int ch) writel(ch, port->membase + CDNS_UART_FIFO_OFFSET); } -static void cdns_early_write(struct console *con, const char *s, unsigned n) +static void __init cdns_early_write(struct console *con, const char *s, + unsigned n) { struct earlycon_device *dev = con->data; diff --git a/kernel/drivers/tty/synclink.c b/kernel/drivers/tty/synclink.c index b7991707f..6188059fd 100644 --- a/kernel/drivers/tty/synclink.c +++ b/kernel/drivers/tty/synclink.c @@ -3314,12 +3314,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, -EAGAIN : -ERESTARTSYS; break; } - + dcd = tty_port_carrier_raised(&info->port); - - if (!(port->flags & ASYNC_CLOSING) && (do_clocal || dcd)) - break; - + if (do_clocal || dcd) + break; + if (signal_pending(current)) { retval = -ERESTARTSYS; break; @@ -3398,15 +3397,6 @@ static int mgsl_open(struct tty_struct *tty, struct file * filp) printk("%s(%d):mgsl_open(%s), old ref count = %d\n", __FILE__,__LINE__,tty->driver->name, info->port.count); - /* If port is closing, signal caller to try again */ - if (info->port.flags & ASYNC_CLOSING){ - wait_event_interruptible_tty(tty, info->port.close_wait, - !(info->port.flags & ASYNC_CLOSING)); - retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); - goto cleanup; - } - info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; spin_lock_irqsave(&info->netlock, flags); @@ -4410,7 +4400,8 @@ static void synclink_cleanup(void) printk("Unloading %s: %s\n", driver_name, driver_version); if (serial_driver) { - if ((rc = tty_unregister_driver(serial_driver))) + rc = tty_unregister_driver(serial_driver); + if (rc) printk("%s(%d) failed to unregister tty driver err=%d\n", __FILE__,__LINE__,rc); put_tty_driver(serial_driver); @@ -6634,7 +6625,7 @@ static bool mgsl_get_rx_frame(struct mgsl_struct *info) unsigned char *ptmp = info->intermediate_rxbuffer; if ( !(status & RXSTATUS_CRC_ERROR)) - info->icount.rxok++; + info->icount.rxok++; while(copy_count) { int partial_count; @@ -7751,7 +7742,8 @@ static int hdlcdev_open(struct net_device *dev) printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); /* generic HDLC layer open processing */ - if ((rc = hdlc_open(dev))) + rc = hdlc_open(dev); + if (rc) return rc; /* arbitrate between network and tty opens */ @@ -8018,7 +8010,8 @@ static int hdlcdev_init(struct mgsl_struct *info) /* allocate and initialize network and HDLC layer objects */ - if (!(dev = alloc_hdlcdev(info))) { + dev = alloc_hdlcdev(info); + if (!dev) { printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); return -ENOMEM; } @@ -8039,7 +8032,8 @@ static int hdlcdev_init(struct mgsl_struct *info) hdlc->xmit = hdlcdev_xmit; /* register objects with HDLC layer */ - if ((rc = register_hdlc_device(dev))) { + rc = register_hdlc_device(dev); + if (rc) { printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); free_netdev(dev); return rc; @@ -8075,7 +8069,8 @@ static int synclink_init_one (struct pci_dev *dev, return -EIO; } - if (!(info = mgsl_allocate_device())) { + info = mgsl_allocate_device(); + if (!info) { printk("can't allocate device instance data.\n"); return -EIO; } diff --git a/kernel/drivers/tty/synclink_gt.c b/kernel/drivers/tty/synclink_gt.c index 0e8c39b6c..6fc39fbfc 100644 --- a/kernel/drivers/tty/synclink_gt.c +++ b/kernel/drivers/tty/synclink_gt.c @@ -672,15 +672,6 @@ static int open(struct tty_struct *tty, struct file *filp) DBGINFO(("%s open, old ref count = %d\n", info->device_name, info->port.count)); - /* If port is closing, signal caller to try again */ - if (info->port.flags & ASYNC_CLOSING){ - wait_event_interruptible_tty(tty, info->port.close_wait, - !(info->port.flags & ASYNC_CLOSING)); - retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); - goto cleanup; - } - mutex_lock(&info->port.mutex); info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; @@ -1539,7 +1530,8 @@ static int hdlcdev_open(struct net_device *dev) DBGINFO(("%s hdlcdev_open\n", dev->name)); /* generic HDLC layer open processing */ - if ((rc = hdlc_open(dev))) + rc = hdlc_open(dev); + if (rc) return rc; /* arbitrate between network and tty opens */ @@ -1803,7 +1795,8 @@ static int hdlcdev_init(struct slgt_info *info) /* allocate and initialize network and HDLC layer objects */ - if (!(dev = alloc_hdlcdev(info))) { + dev = alloc_hdlcdev(info); + if (!dev) { printk(KERN_ERR "%s hdlc device alloc failure\n", info->device_name); return -ENOMEM; } @@ -1824,7 +1817,8 @@ static int hdlcdev_init(struct slgt_info *info) hdlc->xmit = hdlcdev_xmit; /* register objects with HDLC layer */ - if ((rc = register_hdlc_device(dev))) { + rc = register_hdlc_device(dev); + if (rc) { printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); free_netdev(dev); return rc; @@ -1879,7 +1873,8 @@ static void rx_async(struct slgt_info *info) stat = 0; - if ((status = *(p+1) & (BIT1 + BIT0))) { + status = *(p + 1) & (BIT1 + BIT0); + if (status) { if (status & BIT1) icount->parity++; else if (status & BIT0) @@ -3316,9 +3311,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } cd = tty_port_carrier_raised(port); - - if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd )) - break; + if (do_clocal || cd) + break; if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -3755,7 +3749,8 @@ static void slgt_cleanup(void) if (serial_driver) { for (info=slgt_device_list ; info != NULL ; info=info->next_device) tty_unregister_device(serial_driver, info->line); - if ((rc = tty_unregister_driver(serial_driver))) + rc = tty_unregister_driver(serial_driver); + if (rc) DBGERR(("tty_unregister_driver error=%d\n", rc)); put_tty_driver(serial_driver); } diff --git a/kernel/drivers/tty/synclinkmp.c b/kernel/drivers/tty/synclinkmp.c index c3f90910f..fb00a06df 100644 --- a/kernel/drivers/tty/synclinkmp.c +++ b/kernel/drivers/tty/synclinkmp.c @@ -752,15 +752,6 @@ static int open(struct tty_struct *tty, struct file *filp) printk("%s(%d):%s open(), old ref count = %d\n", __FILE__,__LINE__,tty->driver->name, info->port.count); - /* If port is closing, signal caller to try again */ - if (info->port.flags & ASYNC_CLOSING){ - wait_event_interruptible_tty(tty, info->port.close_wait, - !(info->port.flags & ASYNC_CLOSING)); - retval = ((info->port.flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); - goto cleanup; - } - info->port.low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; spin_lock_irqsave(&info->netlock, flags); @@ -1655,7 +1646,8 @@ static int hdlcdev_open(struct net_device *dev) printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); /* generic HDLC layer open processing */ - if ((rc = hdlc_open(dev))) + rc = hdlc_open(dev); + if (rc) return rc; /* arbitrate between network and tty opens */ @@ -1922,7 +1914,8 @@ static int hdlcdev_init(SLMP_INFO *info) /* allocate and initialize network and HDLC layer objects */ - if (!(dev = alloc_hdlcdev(info))) { + dev = alloc_hdlcdev(info); + if (!dev) { printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); return -ENOMEM; } @@ -1943,7 +1936,8 @@ static int hdlcdev_init(SLMP_INFO *info) hdlc->xmit = hdlcdev_xmit; /* register objects with HDLC layer */ - if ((rc = register_hdlc_device(dev))) { + rc = register_hdlc_device(dev); + if (rc) { printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); free_netdev(dev); return rc; @@ -3338,9 +3332,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } cd = tty_port_carrier_raised(port); - - if (!(port->flags & ASYNC_CLOSING) && (do_clocal || cd)) - break; + if (do_clocal || cd) + break; if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -3920,7 +3913,8 @@ static void synclinkmp_cleanup(void) printk("Unloading %s %s\n", driver_name, driver_version); if (serial_driver) { - if ((rc = tty_unregister_driver(serial_driver))) + rc = tty_unregister_driver(serial_driver); + if (rc) printk("%s(%d) failed to unregister tty driver err=%d\n", __FILE__,__LINE__,rc); put_tty_driver(serial_driver); diff --git a/kernel/drivers/tty/sysrq.c b/kernel/drivers/tty/sysrq.c index 9ffdfcf2e..5381a728d 100644 --- a/kernel/drivers/tty/sysrq.c +++ b/kernel/drivers/tty/sysrq.c @@ -353,9 +353,18 @@ static struct sysrq_key_op sysrq_term_op = { static void moom_callback(struct work_struct *ignored) { - if (!out_of_memory(node_zonelist(first_memory_node, GFP_KERNEL), - GFP_KERNEL, 0, NULL, true)) + const gfp_t gfp_mask = GFP_KERNEL; + struct oom_control oc = { + .zonelist = node_zonelist(first_memory_node, gfp_mask), + .nodemask = NULL, + .gfp_mask = gfp_mask, + .order = -1, + }; + + mutex_lock(&oom_lock); + if (!out_of_memory(&oc)) pr_info("OOM request ignored because killer is disabled\n"); + mutex_unlock(&oom_lock); } static DECLARE_WORK(moom_work, moom_callback); @@ -460,6 +469,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = { /* v: May be registered for frame buffer console restore */ NULL, /* v */ &sysrq_showstate_blocked_op, /* w */ + /* x: May be registered on mips for TLB dump */ /* x: May be registered on ppc/powerpc for xmon */ /* x: May be registered on sparc64 for global PMU dump */ NULL, /* x */ @@ -985,7 +995,7 @@ static int sysrq_reset_seq_param_set(const char *buffer, return 0; } -static struct kernel_param_ops param_ops_sysrq_reset_seq = { +static const struct kernel_param_ops param_ops_sysrq_reset_seq = { .get = param_get_ushort, .set = sysrq_reset_seq_param_set, }; @@ -993,6 +1003,10 @@ static struct kernel_param_ops param_ops_sysrq_reset_seq = { #define param_check_sysrq_reset_seq(name, p) \ __param_check(name, p, unsigned short) +/* + * not really modular, but the easiest way to keep compat with existing + * bootargs behaviour is to continue using module_param here. + */ module_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq, &sysrq_reset_seq_len, 0644); @@ -1109,4 +1123,4 @@ static int __init sysrq_init(void) return 0; } -module_init(sysrq_init); +device_initcall(sysrq_init); diff --git a/kernel/drivers/tty/tty_audit.c b/kernel/drivers/tty/tty_audit.c index 90ca08293..3d245cd3d 100644 --- a/kernel/drivers/tty/tty_audit.c +++ b/kernel/drivers/tty/tty_audit.c @@ -265,7 +265,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty, * * Audit @data of @size from @tty, if necessary. */ -void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, +void tty_audit_add_data(struct tty_struct *tty, const void *data, size_t size, unsigned icanon) { struct tty_audit_buf *buf; diff --git a/kernel/drivers/tty/tty_buffer.c b/kernel/drivers/tty/tty_buffer.c index 2f78b77f0..3cd31e0d4 100644 --- a/kernel/drivers/tty/tty_buffer.c +++ b/kernel/drivers/tty/tty_buffer.c @@ -242,7 +242,10 @@ void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) atomic_inc(&buf->priority); mutex_lock(&buf->lock); - while ((next = buf->head->next) != NULL) { + /* paired w/ release in __tty_buffer_request_room; ensures there are + * no pending memory accesses to the freed buffer + */ + while ((next = smp_load_acquire(&buf->head->next)) != NULL) { tty_buffer_free(port, buf->head); buf->head = next; } @@ -286,16 +289,19 @@ static int __tty_buffer_request_room(struct tty_port *port, size_t size, change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL); if (change || left < size) { /* This is the slow path - looking for new buffers to use */ - if ((n = tty_buffer_alloc(port, size)) != NULL) { + n = tty_buffer_alloc(port, size); + if (n != NULL) { n->flags = flags; buf->tail = n; - b->commit = b->used; - /* paired w/ barrier in flush_to_ldisc(); ensures the + /* paired w/ acquire in flush_to_ldisc(); ensures + * flush_to_ldisc() sees buffer data. + */ + smp_store_release(&b->commit, b->used); + /* paired w/ acquire in flush_to_ldisc(); ensures the * latest commit value can be read before the head is * advanced to the next buffer */ - smp_wmb(); - b->next = n; + smp_store_release(&b->next, n); } else if (change) size = 0; else @@ -393,8 +399,11 @@ void tty_schedule_flip(struct tty_port *port) { struct tty_bufhead *buf = &port->buf; - buf->tail->commit = buf->tail->used; - schedule_work(&buf->work); + /* paired w/ acquire in flush_to_ldisc(); ensures + * flush_to_ldisc() sees buffer data. + */ + smp_store_release(&buf->tail->commit, buf->tail->used); + queue_work(system_unbound_wq, &buf->work); } EXPORT_SYMBOL(tty_schedule_flip); @@ -441,10 +450,9 @@ receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count) count = disc->ops->receive_buf2(tty, p, f, count); else { count = min_t(int, count, tty->receive_room); - if (count) + if (count && disc->ops->receive_buf) disc->ops->receive_buf(tty, p, f, count); } - head->read += count; return count; } @@ -468,7 +476,7 @@ static void flush_to_ldisc(struct work_struct *work) struct tty_struct *tty; struct tty_ldisc *disc; - tty = port->itty; + tty = READ_ONCE(port->itty); if (tty == NULL) return; @@ -487,13 +495,15 @@ static void flush_to_ldisc(struct work_struct *work) if (atomic_read(&buf->priority)) break; - next = head->next; - /* paired w/ barrier in __tty_buffer_request_room(); + /* paired w/ release in __tty_buffer_request_room(); * ensures commit value read is not stale if the head * is advancing to the next buffer */ - smp_rmb(); - count = head->commit - head->read; + next = smp_load_acquire(&head->next); + /* paired w/ release in __tty_buffer_request_room() or in + * tty_buffer_flush(); ensures we see the committed buffer data + */ + count = smp_load_acquire(&head->commit) - head->read; if (!count) { if (next == NULL) { check_other_closed(tty); @@ -507,6 +517,7 @@ static void flush_to_ldisc(struct work_struct *work) count = receive_buf(tty, head, count); if (!count) break; + head->read += count; } mutex_unlock(&buf->lock); @@ -576,3 +587,13 @@ void tty_buffer_set_lock_subclass(struct tty_port *port) { lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE); } + +bool tty_buffer_restart_work(struct tty_port *port) +{ + return queue_work(system_unbound_wq, &port->buf.work); +} + +bool tty_buffer_cancel_work(struct tty_port *port) +{ + return cancel_work_sync(&port->buf.work); +} diff --git a/kernel/drivers/tty/tty_io.c b/kernel/drivers/tty/tty_io.c index e56954675..7cef54334 100644 --- a/kernel/drivers/tty/tty_io.c +++ b/kernel/drivers/tty/tty_io.c @@ -106,6 +106,11 @@ #include <linux/nsproxy.h> #undef TTY_DEBUG_HANGUP +#ifdef TTY_DEBUG_HANGUP +# define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args) +#else +# define tty_debug_hangup(tty, f, args...) do { } while (0) +#endif #define TTY_PARANOIA_CHECK 1 #define CHECK_TTY_COUNT 1 @@ -235,7 +240,6 @@ static void tty_del_file(struct file *file) /** * tty_name - return tty naming * @tty: tty structure - * @buf: buffer for output * * Convert a tty structure into a name. The name reflects the kernel * naming policy and if udev is in use may not reflect user space @@ -243,13 +247,11 @@ static void tty_del_file(struct file *file) * Locking: none */ -char *tty_name(struct tty_struct *tty, char *buf) +const char *tty_name(const struct tty_struct *tty) { if (!tty) /* Hmm. NULL pointer. That's fun. */ - strcpy(buf, "NULL tty"); - else - strcpy(buf, tty->name); - return buf; + return "NULL tty"; + return tty->name; } EXPORT_SYMBOL(tty_name); @@ -388,39 +390,48 @@ EXPORT_SYMBOL_GPL(tty_find_polling_driver); * Locking: ctrl_lock */ -int tty_check_change(struct tty_struct *tty) +int __tty_check_change(struct tty_struct *tty, int sig) { unsigned long flags; + struct pid *pgrp, *tty_pgrp; int ret = 0; if (current->signal->tty != tty) return 0; + rcu_read_lock(); + pgrp = task_pgrp(current); + spin_lock_irqsave(&tty->ctrl_lock, flags); + tty_pgrp = tty->pgrp; + spin_unlock_irqrestore(&tty->ctrl_lock, flags); - if (!tty->pgrp) { - printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n"); - goto out_unlock; + if (tty_pgrp && pgrp != tty->pgrp) { + if (is_ignored(sig)) { + if (sig == SIGTTIN) + ret = -EIO; + } else if (is_current_pgrp_orphaned()) + ret = -EIO; + else { + kill_pgrp(pgrp, sig, 1); + set_thread_flag(TIF_SIGPENDING); + ret = -ERESTARTSYS; + } } - if (task_pgrp(current) == tty->pgrp) - goto out_unlock; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - if (is_ignored(SIGTTOU)) - goto out; - if (is_current_pgrp_orphaned()) { - ret = -EIO; - goto out; + rcu_read_unlock(); + + if (!tty_pgrp) { + pr_warn("%s: tty_check_change: sig=%d, tty->pgrp == NULL!\n", + tty_name(tty), sig); } - kill_pgrp(task_pgrp(current), SIGTTOU, 1); - set_thread_flag(TIF_SIGPENDING); - ret = -ERESTARTSYS; -out: - return ret; -out_unlock: - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + return ret; } +int tty_check_change(struct tty_struct *tty) +{ + return __tty_check_change(tty, SIGTTOU); +} EXPORT_SYMBOL(tty_check_change); static ssize_t hung_up_tty_read(struct file *file, char __user *buf, @@ -527,7 +538,8 @@ static void __proc_set_tty(struct tty_struct *tty) spin_unlock_irqrestore(&tty->ctrl_lock, flags); tty->session = get_pid(task_session(current)); if (current->signal->tty) { - printk(KERN_DEBUG "tty not NULL!!\n"); + tty_debug(tty, "current tty %s not NULL!!\n", + current->signal->tty->name); tty_kref_put(current->signal->tty); } put_pid(current->signal->tty_old_pgrp); @@ -769,10 +781,7 @@ static void do_tty_hangup(struct work_struct *work) void tty_hangup(struct tty_struct *tty) { -#ifdef TTY_DEBUG_HANGUP - char buf[64]; - printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf)); -#endif + tty_debug_hangup(tty, "\n"); schedule_work(&tty->hangup_work); } @@ -789,11 +798,7 @@ EXPORT_SYMBOL(tty_hangup); void tty_vhangup(struct tty_struct *tty) { -#ifdef TTY_DEBUG_HANGUP - char buf[64]; - - printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); -#endif + tty_debug_hangup(tty, "\n"); __tty_hangup(tty, 0); } @@ -830,11 +835,7 @@ void tty_vhangup_self(void) static void tty_vhangup_session(struct tty_struct *tty) { -#ifdef TTY_DEBUG_HANGUP - char buf[64]; - - printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty, buf)); -#endif + tty_debug_hangup(tty, "\n"); __tty_hangup(tty, 1); } @@ -928,12 +929,8 @@ void disassociate_ctty(int on_exit) tty->pgrp = NULL; spin_unlock_irqrestore(&tty->ctrl_lock, flags); tty_kref_put(tty); - } else { -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "error attempted to write to tty [0x%p]" - " = NULL", tty); -#endif - } + } else + tty_debug_hangup(tty, "no current tty\n"); spin_unlock_irq(¤t->sighand->siglock); /* Now clear signal->tty under the lock */ @@ -1203,11 +1200,9 @@ void tty_write_message(struct tty_struct *tty, char *msg) if (tty) { mutex_lock(&tty->atomic_write_lock); tty_lock(tty); - if (tty->ops->write && tty->count > 0) { - tty_unlock(tty); + if (tty->ops->write && tty->count > 0) tty->ops->write(tty, msg, strlen(msg)); - } else - tty_unlock(tty); + tty_unlock(tty); tty_write_unlock(tty); } return; @@ -1287,18 +1282,22 @@ int tty_send_xchar(struct tty_struct *tty, char ch) int was_stopped = tty->stopped; if (tty->ops->send_xchar) { + down_read(&tty->termios_rwsem); tty->ops->send_xchar(tty, ch); + up_read(&tty->termios_rwsem); return 0; } if (tty_write_lock(tty, 0) < 0) return -ERESTARTSYS; + down_read(&tty->termios_rwsem); if (was_stopped) start_tty(tty); tty->ops->write(tty, &ch, 1); if (was_stopped) stop_tty(tty); + up_read(&tty->termios_rwsem); tty_write_unlock(tty); return 0; } @@ -1463,13 +1462,13 @@ static int tty_reopen(struct tty_struct *tty) { struct tty_driver *driver = tty->driver; - if (!tty->count) - return -EIO; - if (driver->type == TTY_DRIVER_TYPE_PTY && driver->subtype == PTY_TYPE_MASTER) return -EIO; + if (!tty->count) + return -EAGAIN; + if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) return -EBUSY; @@ -1694,7 +1693,7 @@ static void release_tty(struct tty_struct *tty, int idx) tty->port->itty = NULL; if (tty->link) tty->link->port->itty = NULL; - cancel_work_sync(&tty->port->buf.work); + tty_buffer_cancel_work(tty->port); tty_kref_put(tty->link); tty_kref_put(tty); @@ -1713,8 +1712,7 @@ static int tty_release_checks(struct tty_struct *tty, int idx) { #ifdef TTY_PARANOIA_CHECK if (idx < 0 || idx >= tty->driver->num) { - printk(KERN_DEBUG "%s: bad idx when trying to free (%s)\n", - __func__, tty->name); + tty_debug(tty, "bad idx %d\n", idx); return -1; } @@ -1723,20 +1721,20 @@ static int tty_release_checks(struct tty_struct *tty, int idx) return 0; if (tty != tty->driver->ttys[idx]) { - printk(KERN_DEBUG "%s: driver.table[%d] not tty for (%s)\n", - __func__, idx, tty->name); + tty_debug(tty, "bad driver table[%d] = %p\n", + idx, tty->driver->ttys[idx]); return -1; } if (tty->driver->other) { struct tty_struct *o_tty = tty->link; if (o_tty != tty->driver->other->ttys[idx]) { - printk(KERN_DEBUG "%s: other->table[%d] not o_tty for (%s)\n", - __func__, idx, tty->name); + tty_debug(tty, "bad other table[%d] = %p\n", + idx, tty->driver->other->ttys[idx]); return -1; } if (o_tty->link != tty) { - printk(KERN_DEBUG "%s: bad pty pointers\n", __func__); + tty_debug(tty, "bad link = %p\n", o_tty->link); return -1; } } @@ -1769,7 +1767,6 @@ int tty_release(struct inode *inode, struct file *filp) struct tty_struct *o_tty = NULL; int do_sleep, final; int idx; - char buf[64]; long timeout = 0; int once = 1; @@ -1791,10 +1788,7 @@ int tty_release(struct inode *inode, struct file *filp) return 0; } -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s (tty count=%d)...\n", __func__, - tty_name(tty, buf), tty->count); -#endif + tty_debug_hangup(tty, "(tty count=%d)...\n", tty->count); if (tty->ops->close) tty->ops->close(tty, filp); @@ -1844,7 +1838,7 @@ int tty_release(struct inode *inode, struct file *filp) if (once) { once = 0; printk(KERN_WARNING "%s: %s: read/write wait queue active!\n", - __func__, tty_name(tty, buf)); + __func__, tty_name(tty)); } schedule_timeout_killable(timeout); if (timeout < 120 * HZ) @@ -1856,13 +1850,13 @@ int tty_release(struct inode *inode, struct file *filp) if (o_tty) { if (--o_tty->count < 0) { printk(KERN_WARNING "%s: bad pty slave count (%d) for %s\n", - __func__, o_tty->count, tty_name(o_tty, buf)); + __func__, o_tty->count, tty_name(o_tty)); o_tty->count = 0; } } if (--tty->count < 0) { printk(KERN_WARNING "%s: bad tty->count (%d) for %s\n", - __func__, tty->count, tty_name(tty, buf)); + __func__, tty->count, tty_name(tty)); tty->count = 0; } @@ -1904,9 +1898,7 @@ int tty_release(struct inode *inode, struct file *filp) if (!final) return 0; -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty, buf)); -#endif + tty_debug_hangup(tty, "final close\n"); /* * Ask the line discipline code to release its structures */ @@ -1915,9 +1907,7 @@ int tty_release(struct inode *inode, struct file *filp) /* Wait for pending work before tty destruction commmences */ tty_flush_works(tty); -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, tty_name(tty, buf)); -#endif + tty_debug_hangup(tty, "freeing structure...\n"); /* * The release_tty function takes care of the details of clearing * the slots and preserving the termios structure. The tty_unlock_pair @@ -2079,7 +2069,12 @@ retry_open: if (tty) { mutex_unlock(&tty_mutex); - tty_lock(tty); + retval = tty_lock_interruptible(tty); + if (retval) { + if (retval == -EINTR) + retval = -ERESTARTSYS; + goto err_unref; + } /* safe to drop the kref from tty_driver_lookup_tty() */ tty_kref_put(tty); retval = tty_reopen(tty); @@ -2097,7 +2092,11 @@ retry_open: if (IS_ERR(tty)) { retval = PTR_ERR(tty); - goto err_file; + if (retval != -EAGAIN || signal_pending(current)) + goto err_file; + tty_free_file(filp); + schedule(); + goto retry_open; } tty_add_file(tty, filp); @@ -2106,9 +2105,9 @@ retry_open: if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) noctty = 1; -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: opening %s...\n", __func__, tty->name); -#endif + + tty_debug_hangup(tty, "(tty count=%d)\n", tty->count); + if (tty->ops->open) retval = tty->ops->open(tty, filp); else @@ -2116,10 +2115,8 @@ retry_open: filp->f_flags = saved_flags; if (retval) { -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__, - retval, tty->name); -#endif + tty_debug_hangup(tty, "error %d, releasing...\n", retval); + tty_unlock(tty); /* need to call tty_release without BTM */ tty_release(inode, filp); if (retval != -ERESTARTSYS) @@ -2144,14 +2141,31 @@ retry_open: if (!noctty && current->signal->leader && !current->signal->tty && - tty->session == NULL) - __proc_set_tty(tty); + tty->session == NULL) { + /* + * Don't let a process that only has write access to the tty + * obtain the privileges associated with having a tty as + * controlling terminal (being able to reopen it with full + * access through /dev/tty, being able to perform pushback). + * Many distributions set the group of all ttys to "tty" and + * grant write-only access to all terminals for setgid tty + * binaries, which should not imply full privileges on all ttys. + * + * This could theoretically break old code that performs open() + * on a write-only file descriptor. In that case, it might be + * necessary to also permit this if + * inode_permission(inode, MAY_READ) == 0. + */ + if (filp->f_mode & FMODE_READ) + __proc_set_tty(tty); + } spin_unlock_irq(¤t->sighand->siglock); read_unlock(&tasklist_lock); tty_unlock(tty); return 0; err_unlock: mutex_unlock(&tty_mutex); +err_unref: /* after locks to avoid deadlock */ if (!IS_ERR_OR_NULL(driver)) tty_driver_kref_put(driver); @@ -2434,7 +2448,7 @@ static int fionbio(struct file *file, int __user *p) * Takes ->siglock() when updating signal->tty */ -static int tiocsctty(struct tty_struct *tty, int arg) +static int tiocsctty(struct tty_struct *tty, struct file *file, int arg) { int ret = 0; @@ -2468,6 +2482,13 @@ static int tiocsctty(struct tty_struct *tty, int arg) goto unlock; } } + + /* See the comment in tty_open(). */ + if ((file->f_mode & FMODE_READ) == 0 && !capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + goto unlock; + } + proc_set_tty(tty); unlock: read_unlock(&tasklist_lock); @@ -2562,7 +2583,6 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t struct pid *pgrp; pid_t pgrp_nr; int retval = tty_check_change(real_tty); - unsigned long flags; if (retval == -EIO) return -ENOTTY; @@ -2585,10 +2605,10 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t if (session_of_pgrp(pgrp) != task_session(current)) goto out_unlock; retval = 0; - spin_lock_irqsave(&tty->ctrl_lock, flags); + spin_lock_irq(&tty->ctrl_lock); put_pid(real_tty->pgrp); real_tty->pgrp = get_pid(pgrp); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); + spin_unlock_irq(&tty->ctrl_lock); out_unlock: rcu_read_unlock(); return retval; @@ -2643,6 +2663,28 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) } /** + * tiocgetd - get line discipline + * @tty: tty device + * @p: pointer to user data + * + * Retrieves the line discipline id directly from the ldisc. + * + * Locking: waits for ldisc reference (in case the line discipline + * is changing or the tty is being hungup) + */ + +static int tiocgetd(struct tty_struct *tty, int __user *p) +{ + struct tty_ldisc *ld; + int ret; + + ld = tty_ldisc_ref_wait(tty); + ret = put_user(ld->ops->num, p); + tty_ldisc_deref(ld); + return ret; +} + +/** * send_break - performed time break * @tty: device to break on * @duration: timeout in mS @@ -2860,7 +2902,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) no_tty(); return 0; case TIOCSCTTY: - return tiocsctty(tty, arg); + return tiocsctty(tty, file, arg); case TIOCGPGRP: return tiocgpgrp(tty, real_tty, p); case TIOCSPGRP: @@ -2868,7 +2910,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCGSID: return tiocgsid(tty, real_tty, p); case TIOCGETD: - return put_user(tty->ldisc->ops->num, (int __user *)p); + return tiocgetd(tty, p); case TIOCSETD: return tiocsetd(tty, p); case TIOCVHANGUP: @@ -3167,10 +3209,18 @@ struct class *tty_class; static int tty_cdev_add(struct tty_driver *driver, dev_t dev, unsigned int index, unsigned int count) { + int err; + /* init here, since reused cdevs cause crashes */ - cdev_init(&driver->cdevs[index], &tty_fops); - driver->cdevs[index].owner = driver->owner; - return cdev_add(&driver->cdevs[index], dev, count); + driver->cdevs[index] = cdev_alloc(); + if (!driver->cdevs[index]) + return -ENOMEM; + driver->cdevs[index]->ops = &tty_fops; + driver->cdevs[index]->owner = driver->owner; + err = cdev_add(driver->cdevs[index], dev, count); + if (err) + kobject_put(&driver->cdevs[index]->kobj); + return err; } /** @@ -3276,8 +3326,10 @@ struct device *tty_register_device_attr(struct tty_driver *driver, error: put_device(dev); - if (cdev) - cdev_del(&driver->cdevs[index]); + if (cdev) { + cdev_del(driver->cdevs[index]); + driver->cdevs[index] = NULL; + } return ERR_PTR(retval); } EXPORT_SYMBOL_GPL(tty_register_device_attr); @@ -3297,8 +3349,10 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) { device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); - if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) - cdev_del(&driver->cdevs[index]); + if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) { + cdev_del(driver->cdevs[index]); + driver->cdevs[index] = NULL; + } } EXPORT_SYMBOL(tty_unregister_device); @@ -3363,6 +3417,7 @@ err_free_all: kfree(driver->ports); kfree(driver->ttys); kfree(driver->termios); + kfree(driver->cdevs); kfree(driver); return ERR_PTR(err); } @@ -3391,7 +3446,7 @@ static void destruct_tty_driver(struct kref *kref) } proc_tty_unregister_driver(driver); if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) - cdev_del(&driver->cdevs[0]); + cdev_del(driver->cdevs[0]); } kfree(driver->cdevs); kfree(driver->ports); diff --git a/kernel/drivers/tty/tty_ioctl.c b/kernel/drivers/tty/tty_ioctl.c index 8e53fe469..1445dd39a 100644 --- a/kernel/drivers/tty/tty_ioctl.c +++ b/kernel/drivers/tty/tty_ioctl.c @@ -26,6 +26,12 @@ #undef TTY_DEBUG_WAIT_UNTIL_SENT +#ifdef TTY_DEBUG_WAIT_UNTIL_SENT +# define tty_debug_wait_until_sent(tty, f, args...) tty_debug(tty, f, ##args) +#else +# define tty_debug_wait_until_sent(tty, f, args...) do {} while (0) +#endif + #undef DEBUG /* @@ -210,11 +216,8 @@ int tty_unthrottle_safe(struct tty_struct *tty) void tty_wait_until_sent(struct tty_struct *tty, long timeout) { -#ifdef TTY_DEBUG_WAIT_UNTIL_SENT - char buf[64]; + tty_debug_wait_until_sent(tty, "\n"); - printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf)); -#endif if (!timeout) timeout = MAX_SCHEDULE_TIMEOUT; @@ -1144,16 +1147,12 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, spin_unlock_irq(&tty->flow_lock); break; case TCIOFF: - down_read(&tty->termios_rwsem); if (STOP_CHAR(tty) != __DISABLED_CHAR) retval = tty_send_xchar(tty, STOP_CHAR(tty)); - up_read(&tty->termios_rwsem); break; case TCION: - down_read(&tty->termios_rwsem); if (START_CHAR(tty) != __DISABLED_CHAR) retval = tty_send_xchar(tty, START_CHAR(tty)); - up_read(&tty->termios_rwsem); break; default: return -EINVAL; diff --git a/kernel/drivers/tty/tty_ldisc.c b/kernel/drivers/tty/tty_ldisc.c index 3737f5527..629e3c865 100644 --- a/kernel/drivers/tty/tty_ldisc.c +++ b/kernel/drivers/tty/tty_ldisc.c @@ -22,10 +22,7 @@ #undef LDISC_DEBUG_HANGUP #ifdef LDISC_DEBUG_HANGUP -#define tty_ldisc_debug(tty, f, args...) ({ \ - char __b[64]; \ - printk(KERN_DEBUG "%s: %s: " f, __func__, tty_name(tty, __b), ##args); \ -}) +#define tty_ldisc_debug(tty, f, args...) tty_debug(tty, f, ##args) #else #define tty_ldisc_debug(tty, f, args...) #endif @@ -322,7 +319,7 @@ __tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout) static inline void __tty_ldisc_unlock(struct tty_struct *tty) { - return ldsem_up_write(&tty->ldisc_sem); + ldsem_up_write(&tty->ldisc_sem); } static int __lockfunc @@ -450,6 +447,8 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) ret = ld->ops->open(tty); if (ret) clear_bit(TTY_LDISC_OPEN, &tty->flags); + + tty_ldisc_debug(tty, "%p: opened\n", tty->ldisc); return ret; } return 0; @@ -470,6 +469,7 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) clear_bit(TTY_LDISC_OPEN, &tty->flags); if (ld->ops->close) ld->ops->close(tty); + tty_ldisc_debug(tty, "%p: closed\n", tty->ldisc); } /** @@ -483,7 +483,6 @@ static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) { - char buf[64]; struct tty_ldisc *new_ldisc; int r; @@ -504,7 +503,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) if (r < 0) panic("Couldn't open N_TTY ldisc for " "%s --- error %d.", - tty_name(tty, buf), r); + tty_name(tty), r); } } @@ -593,7 +592,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) /* Restart the work queue in case no characters kick it off. Safe if already running */ - schedule_work(&tty->port->buf.work); + tty_buffer_restart_work(tty->port); tty_unlock(tty); return retval; @@ -664,7 +663,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) int reset = tty->driver->flags & TTY_DRIVER_RESET_TERMIOS; int err = 0; - tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc); + tty_ldisc_debug(tty, "%p: closing\n", tty->ldisc); ld = tty_ldisc_ref(tty); if (ld != NULL) { @@ -714,7 +713,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) if (reset) tty_reset_termios(tty); - tty_ldisc_debug(tty, "re-opened ldisc: %p\n", tty->ldisc); + tty_ldisc_debug(tty, "%p: re-opened\n", tty->ldisc); } /** @@ -778,8 +777,6 @@ void tty_ldisc_release(struct tty_struct *tty) * it does not race with the set_ldisc code path. */ - tty_ldisc_debug(tty, "closing ldisc: %p\n", tty->ldisc); - tty_ldisc_lock_pair(tty, o_tty); tty_ldisc_kill(tty); if (o_tty) @@ -789,7 +786,7 @@ void tty_ldisc_release(struct tty_struct *tty) /* And the memory resources remaining (buffers, termios) will be disposed of when the kref hits zero */ - tty_ldisc_debug(tty, "ldisc closed\n"); + tty_ldisc_debug(tty, "released\n"); } /** diff --git a/kernel/drivers/tty/tty_ldsem.c b/kernel/drivers/tty/tty_ldsem.c index 0ffb0cbe2..ad7eba5ca 100644 --- a/kernel/drivers/tty/tty_ldsem.c +++ b/kernel/drivers/tty/tty_ldsem.c @@ -299,7 +299,8 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout) timeout = schedule_timeout(timeout); raw_spin_lock_irq(&sem->wait_lock); set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if ((locked = writer_trylock(sem))) + locked = writer_trylock(sem); + if (locked) break; } diff --git a/kernel/drivers/tty/tty_mutex.c b/kernel/drivers/tty/tty_mutex.c index 0efcf713b..d09293bc0 100644 --- a/kernel/drivers/tty/tty_mutex.c +++ b/kernel/drivers/tty/tty_mutex.c @@ -22,6 +22,14 @@ void __lockfunc tty_lock(struct tty_struct *tty) } EXPORT_SYMBOL(tty_lock); +int tty_lock_interruptible(struct tty_struct *tty) +{ + if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty)) + return -EIO; + tty_kref_get(tty); + return mutex_lock_interruptible(&tty->legacy_mutex); +} + void __lockfunc tty_unlock(struct tty_struct *tty) { if (tty->magic != TTY_MAGIC) { diff --git a/kernel/drivers/tty/tty_port.c b/kernel/drivers/tty/tty_port.c index 40b31835f..482f33f20 100644 --- a/kernel/drivers/tty/tty_port.c +++ b/kernel/drivers/tty/tty_port.c @@ -22,7 +22,6 @@ void tty_port_init(struct tty_port *port) memset(port, 0, sizeof(*port)); tty_buffer_init(port); init_waitqueue_head(&port->open_wait); - init_waitqueue_head(&port->close_wait); init_waitqueue_head(&port->delta_msr_wait); mutex_init(&port->mutex); mutex_init(&port->buf_mutex); @@ -131,7 +130,7 @@ EXPORT_SYMBOL(tty_port_free_xmit_buf); */ void tty_port_destroy(struct tty_port *port) { - cancel_work_sync(&port->buf.work); + tty_buffer_cancel_work(port); tty_buffer_free_all(port); } EXPORT_SYMBOL(tty_port_destroy); @@ -363,16 +362,6 @@ int tty_port_block_til_ready(struct tty_port *port, unsigned long flags; DEFINE_WAIT(wait); - /* block if port is in the process of being closed */ - if (port->flags & ASYNC_CLOSING) { - wait_event_interruptible_tty(tty, port->close_wait, - !(port->flags & ASYNC_CLOSING)); - if (port->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; - } - /* if non-blocking mode is set we can pass directly to open unless the port has just hung up or is in another error state */ if (tty->flags & (1 << TTY_IO_ERROR)) { @@ -423,8 +412,7 @@ int tty_port_block_til_ready(struct tty_port *port, * Never ask drivers if CLOCAL is set, this causes troubles * on some hardware. */ - if (!(port->flags & ASYNC_CLOSING) && - (do_clocal || tty_port_carrier_raised(port))) + if (do_clocal || tty_port_carrier_raised(port)) break; if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -463,10 +451,7 @@ static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty) schedule_timeout_interruptible(timeout); } -/* Caller holds tty lock. - * NB: may drop and reacquire tty lock (in tty_wait_until_sent_from_close()) - * so tty and tty port may have changed state (but not hung up or reopened). - */ +/* Caller holds tty lock. */ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct file *filp) { @@ -502,7 +487,7 @@ int tty_port_close_start(struct tty_port *port, if (tty->flow_stopped) tty_driver_flush_buffer(tty); if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent_from_close(tty, port->closing_wait); + tty_wait_until_sent(tty, port->closing_wait); if (port->drain_delay) tty_port_drain_delay(port, tty); } @@ -534,7 +519,6 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) wake_up_interruptible(&port->open_wait); } port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); - wake_up_interruptible(&port->close_wait); spin_unlock_irqrestore(&port->lock, flags); } EXPORT_SYMBOL(tty_port_close_end); @@ -543,10 +527,6 @@ EXPORT_SYMBOL(tty_port_close_end); * tty_port_close * * Caller holds tty lock - * - * NB: may drop and reacquire tty lock (in tty_port_close_start()-> - * tty_wait_until_sent_from_close()) so tty and tty_port may have changed - * state (but not hung up or reopened). */ void tty_port_close(struct tty_port *port, struct tty_struct *tty, struct file *filp) diff --git a/kernel/drivers/tty/vt/consolemap.c b/kernel/drivers/tty/vt/consolemap.c index 59b25e039..c8c91f047 100644 --- a/kernel/drivers/tty/vt/consolemap.c +++ b/kernel/drivers/tty/vt/consolemap.c @@ -261,19 +261,22 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode) int m; if (glyph < 0 || glyph >= MAX_GLYPH) return 0; - else if (!(p = *conp->vc_uni_pagedir_loc)) - return glyph; - else if (use_unicode) { - if (!p->inverse_trans_unicode) + else { + p = *conp->vc_uni_pagedir_loc; + if (!p) return glyph; - else - return p->inverse_trans_unicode[glyph]; - } else { - m = inv_translate[conp->vc_num]; - if (!p->inverse_translations[m]) - return glyph; - else - return p->inverse_translations[m][glyph]; + else if (use_unicode) { + if (!p->inverse_trans_unicode) + return glyph; + else + return p->inverse_trans_unicode[glyph]; + } else { + m = inv_translate[conp->vc_num]; + if (!p->inverse_translations[m]) + return glyph; + else + return p->inverse_translations[m][glyph]; + } } } EXPORT_SYMBOL_GPL(inverse_translate); @@ -397,7 +400,8 @@ static void con_release_unimap(struct uni_pagedir *p) if (p == dflt) dflt = NULL; for (i = 0; i < 32; i++) { - if ((p1 = p->uni_pgdir[i]) != NULL) { + p1 = p->uni_pgdir[i]; + if (p1 != NULL) { for (j = 0; j < 32; j++) kfree(p1[j]); kfree(p1); @@ -473,14 +477,16 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) int i, n; u16 **p1, *p2; - if (!(p1 = p->uni_pgdir[n = unicode >> 11])) { + p1 = p->uni_pgdir[n = unicode >> 11]; + if (!p1) { p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL); if (!p1) return -ENOMEM; for (i = 0; i < 32; i++) p1[i] = NULL; } - if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) { + p2 = p1[n = (unicode >> 6) & 0x1f]; + if (!p2) { p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL); if (!p2) return -ENOMEM; memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */ @@ -569,10 +575,12 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) * entries from "p" (old) to "q" (new). */ l = 0; /* unicode value */ - for (i = 0; i < 32; i++) - if ((p1 = p->uni_pgdir[i])) - for (j = 0; j < 32; j++) - if ((p2 = p1[j])) { + for (i = 0; i < 32; i++) { + p1 = p->uni_pgdir[i]; + if (p1) + for (j = 0; j < 32; j++) { + p2 = p1[j]; + if (p2) { for (k = 0; k < 64; k++, l++) if (p2[k] != 0xffff) { /* @@ -593,9 +601,11 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) /* Account for row of 64 empty entries */ l += 64; } + } else /* Account for empty table */ l += 32 * 64; + } /* * Finished copying font table, set vc_uni_pagedir to new table @@ -735,10 +745,12 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni ect = 0; if (*vc->vc_uni_pagedir_loc) { p = *vc->vc_uni_pagedir_loc; - for (i = 0; i < 32; i++) - if ((p1 = p->uni_pgdir[i])) - for (j = 0; j < 32; j++) - if ((p2 = *(p1++))) + for (i = 0; i < 32; i++) { + p1 = p->uni_pgdir[i]; + if (p1) + for (j = 0; j < 32; j++) { + p2 = *(p1++); + if (p2) for (k = 0; k < 64; k++) { if (*p2 < MAX_GLYPH && ect++ < ct) { __put_user((u_short)((i<<11)+(j<<6)+k), @@ -749,6 +761,8 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni } p2++; } + } + } } __put_user(ect, uct); console_unlock(); diff --git a/kernel/drivers/tty/vt/keyboard.c b/kernel/drivers/tty/vt/keyboard.c index 8a89f6e77..6f0336fff 100644 --- a/kernel/drivers/tty/vt/keyboard.c +++ b/kernel/drivers/tty/vt/keyboard.c @@ -33,6 +33,7 @@ #include <linux/string.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/leds.h> #include <linux/kbd_kern.h> #include <linux/kbd_diacr.h> @@ -129,7 +130,7 @@ static char rep; /* flag telling character repeat */ static int shift_state = 0; -static unsigned char ledstate = 0xff; /* undefined */ +static unsigned int ledstate = -1U; /* undefined */ static unsigned char ledioctl; /* @@ -961,6 +962,122 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) } } +#if IS_ENABLED(CONFIG_INPUT_LEDS) && IS_ENABLED(CONFIG_LEDS_TRIGGERS) + +struct kbd_led_trigger { + struct led_trigger trigger; + unsigned int mask; +}; + +static void kbd_led_trigger_activate(struct led_classdev *cdev) +{ + struct kbd_led_trigger *trigger = + container_of(cdev->trigger, struct kbd_led_trigger, trigger); + + tasklet_disable(&keyboard_tasklet); + if (ledstate != -1U) + led_trigger_event(&trigger->trigger, + ledstate & trigger->mask ? + LED_FULL : LED_OFF); + tasklet_enable(&keyboard_tasklet); +} + +#define KBD_LED_TRIGGER(_led_bit, _name) { \ + .trigger = { \ + .name = _name, \ + .activate = kbd_led_trigger_activate, \ + }, \ + .mask = BIT(_led_bit), \ + } + +#define KBD_LOCKSTATE_TRIGGER(_led_bit, _name) \ + KBD_LED_TRIGGER((_led_bit) + 8, _name) + +static struct kbd_led_trigger kbd_led_triggers[] = { + KBD_LED_TRIGGER(VC_SCROLLOCK, "kbd-scrollock"), + KBD_LED_TRIGGER(VC_NUMLOCK, "kbd-numlock"), + KBD_LED_TRIGGER(VC_CAPSLOCK, "kbd-capslock"), + KBD_LED_TRIGGER(VC_KANALOCK, "kbd-kanalock"), + + KBD_LOCKSTATE_TRIGGER(VC_SHIFTLOCK, "kbd-shiftlock"), + KBD_LOCKSTATE_TRIGGER(VC_ALTGRLOCK, "kbd-altgrlock"), + KBD_LOCKSTATE_TRIGGER(VC_CTRLLOCK, "kbd-ctrllock"), + KBD_LOCKSTATE_TRIGGER(VC_ALTLOCK, "kbd-altlock"), + KBD_LOCKSTATE_TRIGGER(VC_SHIFTLLOCK, "kbd-shiftllock"), + KBD_LOCKSTATE_TRIGGER(VC_SHIFTRLOCK, "kbd-shiftrlock"), + KBD_LOCKSTATE_TRIGGER(VC_CTRLLLOCK, "kbd-ctrlllock"), + KBD_LOCKSTATE_TRIGGER(VC_CTRLRLOCK, "kbd-ctrlrlock"), +}; + +static void kbd_propagate_led_state(unsigned int old_state, + unsigned int new_state) +{ + struct kbd_led_trigger *trigger; + unsigned int changed = old_state ^ new_state; + int i; + + for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) { + trigger = &kbd_led_triggers[i]; + + if (changed & trigger->mask) + led_trigger_event(&trigger->trigger, + new_state & trigger->mask ? + LED_FULL : LED_OFF); + } +} + +static int kbd_update_leds_helper(struct input_handle *handle, void *data) +{ + unsigned int led_state = *(unsigned int *)data; + + if (test_bit(EV_LED, handle->dev->evbit)) + kbd_propagate_led_state(~led_state, led_state); + + return 0; +} + +static void kbd_init_leds(void) +{ + int error; + int i; + + for (i = 0; i < ARRAY_SIZE(kbd_led_triggers); i++) { + error = led_trigger_register(&kbd_led_triggers[i].trigger); + if (error) + pr_err("error %d while registering trigger %s\n", + error, kbd_led_triggers[i].trigger.name); + } +} + +#else + +static int kbd_update_leds_helper(struct input_handle *handle, void *data) +{ + unsigned int leds = *(unsigned int *)data; + + if (test_bit(EV_LED, handle->dev->evbit)) { + input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); + input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); + input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); + input_inject_event(handle, EV_SYN, SYN_REPORT, 0); + } + + return 0; +} + +static void kbd_propagate_led_state(unsigned int old_state, + unsigned int new_state) +{ + input_handler_for_each_handle(&kbd_handler, &new_state, + kbd_update_leds_helper); +} + +static void kbd_init_leds(void) +{ +} + +#endif + /* * The leds display either (i) the status of NumLock, CapsLock, ScrollLock, * or (ii) whatever pattern of lights people want to show using KDSETLED, @@ -968,7 +1085,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) */ static unsigned char getledstate(void) { - return ledstate; + return ledstate & 0xff; } void setledstate(struct kbd_struct *kb, unsigned int led) @@ -995,20 +1112,6 @@ static inline unsigned char getleds(void) return kb->ledflagstate; } -static int kbd_update_leds_helper(struct input_handle *handle, void *data) -{ - unsigned char leds = *(unsigned char *)data; - - if (test_bit(EV_LED, handle->dev->evbit)) { - input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01)); - input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02)); - input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04)); - input_inject_event(handle, EV_SYN, SYN_REPORT, 0); - } - - return 0; -} - /** * vt_get_leds - helper for braille console * @console: console to read @@ -1085,24 +1188,23 @@ void vt_kbd_con_stop(int console) } /* - * This is the tasklet that updates LED state on all keyboards - * attached to the box. The reason we use tasklet is that we - * need to handle the scenario when keyboard handler is not - * registered yet but we already getting updates from the VT to - * update led state. + * This is the tasklet that updates LED state of LEDs using standard + * keyboard triggers. The reason we use tasklet is that we need to + * handle the scenario when keyboard handler is not registered yet + * but we already getting updates from the VT to update led state. */ static void kbd_bh(unsigned long dummy) { - unsigned char leds; + unsigned int leds; unsigned long flags; - + spin_lock_irqsave(&led_lock, flags); leds = getleds(); + leds |= (unsigned int)kbd->lockstate << 8; spin_unlock_irqrestore(&led_lock, flags); if (leds != ledstate) { - input_handler_for_each_handle(&kbd_handler, &leds, - kbd_update_leds_helper); + kbd_propagate_led_state(ledstate, leds); ledstate = leds; } } @@ -1450,7 +1552,7 @@ static void kbd_start(struct input_handle *handle) { tasklet_disable(&keyboard_tasklet); - if (ledstate != 0xff) + if (ledstate != -1U) kbd_update_leds_helper(handle, &ledstate); tasklet_enable(&keyboard_tasklet); @@ -1497,6 +1599,8 @@ int __init kbd_init(void) kbd_table[i].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; } + kbd_init_leds(); + error = input_register_handler(&kbd_handler); if (error) return error; diff --git a/kernel/drivers/tty/vt/selection.c b/kernel/drivers/tty/vt/selection.c index ea27804d8..381a2b136 100644 --- a/kernel/drivers/tty/vt/selection.c +++ b/kernel/drivers/tty/vt/selection.c @@ -356,6 +356,7 @@ int paste_selection(struct tty_struct *tty) schedule(); continue; } + __set_current_state(TASK_RUNNING); count = sel_buffer_lth - pasted; count = tty_ldisc_receive_buf(ld, sel_buffer + pasted, NULL, count); diff --git a/kernel/drivers/tty/vt/vt.c b/kernel/drivers/tty/vt/vt.c index 4a24eb2b0..4462d1679 100644 --- a/kernel/drivers/tty/vt/vt.c +++ b/kernel/drivers/tty/vt/vt.c @@ -108,6 +108,7 @@ #define CON_DRIVER_FLAG_MODULE 1 #define CON_DRIVER_FLAG_INIT 2 #define CON_DRIVER_FLAG_ATTR 4 +#define CON_DRIVER_FLAG_ZOMBIE 8 struct con_driver { const struct consw *con; @@ -135,6 +136,7 @@ const struct consw *conswitchp; */ #define DEFAULT_BELL_PITCH 750 #define DEFAULT_BELL_DURATION (HZ/8) +#define DEFAULT_CURSOR_BLINK_MS 200 struct vc vc_cons [MAX_NR_CONSOLES]; @@ -153,6 +155,7 @@ static int set_vesa_blanking(char __user *p); static void set_cursor(struct vc_data *vc); static void hide_cursor(struct vc_data *vc); static void console_callback(struct work_struct *ignored); +static void con_driver_unregister_callback(struct work_struct *ignored); static void blank_screen_t(unsigned long dummy); static void set_palette(struct vc_data *vc); @@ -182,6 +185,7 @@ static int blankinterval = 10*60; core_param(consoleblank, blankinterval, int, 0444); static DECLARE_WORK(console_work, console_callback); +static DECLARE_WORK(con_driver_unregister_work, con_driver_unregister_callback); /* * fg_console is the current virtual console, @@ -738,6 +742,8 @@ static void visual_init(struct vc_data *vc, int num, int init) __module_get(vc->vc_sw->owner); vc->vc_num = num; vc->vc_display_fg = &master_display_fg; + if (vc->vc_uni_pagedir_loc) + con_free_unimap(vc); vc->vc_uni_pagedir_loc = &vc->vc_uni_pagedir; vc->vc_uni_pagedir = NULL; vc->vc_hi_font_mask = 0; @@ -1590,6 +1596,13 @@ static void setterm_command(struct vc_data *vc) case 15: /* activate the previous console */ set_console(last_console); break; + case 16: /* set cursor blink duration in msec */ + if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 && + vc->vc_par[1] <= USHRT_MAX) + vc->vc_cur_blink_ms = vc->vc_par[1]; + else + vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS; + break; } } @@ -1717,6 +1730,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) vc->vc_bell_pitch = DEFAULT_BELL_PITCH; vc->vc_bell_duration = DEFAULT_BELL_DURATION; + vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS; gotoxy(vc, 0, 0); save_cur(vc); @@ -3192,22 +3206,6 @@ err: #ifdef CONFIG_VT_HW_CONSOLE_BINDING -static int con_is_graphics(const struct consw *csw, int first, int last) -{ - int i, retval = 0; - - for (i = first; i <= last; i++) { - struct vc_data *vc = vc_cons[i].d; - - if (vc && vc->vc_mode == KD_GRAPHICS) { - retval = 1; - break; - } - } - - return retval; -} - /* unlocked version of unbind_con_driver() */ int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt) { @@ -3293,8 +3291,7 @@ static int vt_bind(struct con_driver *con) const struct consw *defcsw = NULL, *csw = NULL; int i, more = 1, first = -1, last = -1, deflt = 0; - if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || - con_is_graphics(con->con, con->first, con->last)) + if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE)) goto err; csw = con->con; @@ -3345,8 +3342,7 @@ static int vt_unbind(struct con_driver *con) int i, more = 1, first = -1, last = -1, deflt = 0; int ret; - if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) || - con_is_graphics(con->con, con->first, con->last)) + if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE)) goto err; csw = con->con; @@ -3596,7 +3592,8 @@ static int do_register_con_driver(const struct consw *csw, int first, int last) for (i = 0; i < MAX_NR_CON_DRIVER; i++) { con_driver = ®istered_con_driver[i]; - if (con_driver->con == NULL) { + if (con_driver->con == NULL && + !(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE)) { con_driver->con = csw; con_driver->desc = desc; con_driver->node = i; @@ -3658,16 +3655,20 @@ int do_unregister_con_driver(const struct consw *csw) struct con_driver *con_driver = ®istered_con_driver[i]; if (con_driver->con == csw) { - vtconsole_deinit_device(con_driver); - device_destroy(vtconsole_class, - MKDEV(0, con_driver->node)); + /* + * Defer the removal of the sysfs entries since that + * will acquire the kernfs s_active lock and we can't + * acquire this lock while holding the console lock: + * the unbind sysfs entry imposes already the opposite + * order. Reset con already here to prevent any later + * lookup to succeed and mark this slot as zombie, so + * it won't get reused until we complete the removal + * in the deferred work. + */ con_driver->con = NULL; - con_driver->desc = NULL; - con_driver->dev = NULL; - con_driver->node = 0; - con_driver->flag = 0; - con_driver->first = 0; - con_driver->last = 0; + con_driver->flag = CON_DRIVER_FLAG_ZOMBIE; + schedule_work(&con_driver_unregister_work); + return 0; } } @@ -3676,6 +3677,39 @@ int do_unregister_con_driver(const struct consw *csw) } EXPORT_SYMBOL_GPL(do_unregister_con_driver); +static void con_driver_unregister_callback(struct work_struct *ignored) +{ + int i; + + console_lock(); + + for (i = 0; i < MAX_NR_CON_DRIVER; i++) { + struct con_driver *con_driver = ®istered_con_driver[i]; + + if (!(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE)) + continue; + + console_unlock(); + + vtconsole_deinit_device(con_driver); + device_destroy(vtconsole_class, MKDEV(0, con_driver->node)); + + console_lock(); + + if (WARN_ON_ONCE(con_driver->con)) + con_driver->con = NULL; + con_driver->desc = NULL; + con_driver->dev = NULL; + con_driver->node = 0; + WARN_ON_ONCE(con_driver->flag != CON_DRIVER_FLAG_ZOMBIE); + con_driver->flag = 0; + con_driver->first = 0; + con_driver->last = 0; + } + + console_unlock(); +} + /* * If we support more console drivers, this function is used * when a driver wants to take over some existing consoles |