Received: by 2002:a25:e74b:0:0:0:0:0 with SMTP id e72csp928757ybh; Wed, 22 Jul 2020 17:34:46 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwm+7XfMyJ6Pb2EeUT8sdE1OfIpViP84b34s6a0EkS/OIuikMAllqeXD8CjEjH7DEx++yKV X-Received: by 2002:a17:906:eb4f:: with SMTP id mc15mr623862ejb.435.1595464486005; Wed, 22 Jul 2020 17:34:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1595464485; cv=none; d=google.com; s=arc-20160816; b=mwiMMeRVczKEWuEyYqu4t510sSGVKxP0xWffWXUSNqycLhkAjGSE8K0EDp9w3EF2kk +nZh6M+hKYkFOtEs0sIE01dnHwCzJRmBM2/WYyvBRuNPVNZ8qsVhs68xwAnVY3Y2oFOz nk5JsVuEzTjavGEW1PbjFrgjRyO31z1SRgs6+MYeGNlwYP9b3ujbZVXtutWqGSmslncv 6HjddFuBw2yY4NzWWZ2VlER/Xp8gVmzA7Ewz4sQzanvuNugqksejG/npXwwV9pZLPK+i hSeCTIEmo23lERJuDG2OveFojrBzdl18KfAyJM2IbU1vhAj/5RhA6TWvHZotPFC6SV0H BWKg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=L3tCpwnJL2o+u1tTiYauFTZvkufqOqW8amYt0EKDLBU=; b=T+CsUioU6vDlFK6ZJW35IiBYhBSbz8Avy9LoBh2peQKY1PnXTWLNUWYxLHSWf/RLW8 bsUjL6D19q3K+Flins22ZgAZ64HK2OewW8Fu23VUGGx4SlDUZaFLOCF2EOKndNI8ty6w GnPRpgXrYLlg1GZnYJYoR078bQZtJs3ExMKDp58HSfOL4t/DdCDdYHbG2yKWyUza16hq PseMcrbtPyNRzyCoxv8iVsM0AFRO4Vt3H4Ukjh6WrSJSeQCFUVERnyTkTsCKH5B79v4U wyjFSqZsjw/xKMOLtTEkU70MDJYVWX6QDMvu6IavBftut/tJw4Q+XMq8r+iQIqJTXQ04 Us3A== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id f14si935051edm.269.2020.07.22.17.34.23; Wed, 22 Jul 2020 17:34:45 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733231AbgGWAeL (ORCPT + 99 others); Wed, 22 Jul 2020 20:34:11 -0400 Received: from mail.baikalelectronics.com ([87.245.175.226]:60686 "EHLO mail.baikalelectronics.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728914AbgGWAeI (ORCPT ); Wed, 22 Jul 2020 20:34:08 -0400 Received: from localhost (unknown [127.0.0.1]) by mail.baikalelectronics.ru (Postfix) with ESMTP id CF1628040A68; Thu, 23 Jul 2020 00:34:00 +0000 (UTC) X-Virus-Scanned: amavisd-new at baikalelectronics.ru Received: from mail.baikalelectronics.ru ([127.0.0.1]) by localhost (mail.baikalelectronics.ru [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id AXi9grj894nC; Thu, 23 Jul 2020 03:34:00 +0300 (MSK) From: Serge Semin To: Greg Kroah-Hartman , Jiri Slaby , Andy Shevchenko CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Andy Shevchenko , Maxime Ripard , Will Deacon , Russell King , , , Subject: [PATCH v9 1/4] serial: 8250: Add 8250 port clock update method Date: Thu, 23 Jul 2020 03:33:54 +0300 Message-ID: <20200723003357.26897-2-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20200723003357.26897-1-Sergey.Semin@baikalelectronics.ru> References: <20200723003357.26897-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 Content-Transfer-Encoding: 7BIT Content-Type: text/plain; charset=US-ASCII X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Some platforms can be designed in a way so the UART port reference clock might be asynchronously changed at some point. In Baikal-T1 SoC this may happen due to the reference clock being shared between two UART ports, on the Allwinner SoC the reference clock is derived from the CPU clock, so any CPU frequency change should get to be known/reflected by/in the UART controller as well. But it's not enough to just update the uart_port->uartclk field of the corresponding UART port, the 8250 controller reference clock divisor should be altered so to preserve current baud rate setting. All of these things is done in a coherent way by calling the serial8250_update_uartclk() method provided in this patch. Though note that it isn't supposed to be called from within the UART port callbacks because the locks using to the protect the UART port data are already taken in there. Signed-off-by: Serge Semin --- Changelog v4: - Export serial8250_update_uartclk() symbol for GPL modules only. Changelog v7: - Wake the device up on the serial port divider update. --- drivers/tty/serial/8250/8250_port.c | 40 +++++++++++++++++++++++++++++ include/linux/serial_8250.h | 2 ++ 2 files changed, 42 insertions(+) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 1632f7d25acc..f19757ef4999 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2631,6 +2631,46 @@ static unsigned int serial8250_get_baud_rate(struct uart_port *port, (port->uartclk + tolerance) / 16); } +/* + * Note in order to avoid the tty port mutex deadlock don't use the next method + * within the uart port callbacks. Primarily it's supposed to be utilized to + * handle a sudden reference clock rate change. + */ +void serial8250_update_uartclk(struct uart_port *port, unsigned int uartclk) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned int baud, quot, frac = 0; + struct ktermios *termios; + unsigned long flags; + + mutex_lock(&port->state->port.mutex); + + if (port->uartclk == uartclk) + goto out_lock; + + port->uartclk = uartclk; + termios = &port->state->port.tty->termios; + + baud = serial8250_get_baud_rate(port, termios, NULL); + quot = serial8250_get_divisor(port, baud, &frac); + + serial8250_rpm_get(up); + spin_lock_irqsave(&port->lock, flags); + + uart_update_timeout(port, termios->c_cflag, baud); + + serial8250_set_divisor(port, baud, quot, frac); + serial_port_out(port, UART_LCR, up->lcr); + serial8250_out_MCR(up, UART_MCR_DTR | UART_MCR_RTS); + + spin_unlock_irqrestore(&port->lock, flags); + serial8250_rpm_put(up); + +out_lock: + mutex_unlock(&port->state->port.mutex); +} +EXPORT_SYMBOL_GPL(serial8250_update_uartclk); + void serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 6545f8cfc8fa..2b70f736b091 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -155,6 +155,8 @@ extern int early_serial_setup(struct uart_port *port); extern int early_serial8250_setup(struct earlycon_device *device, const char *options); +extern void serial8250_update_uartclk(struct uart_port *port, + unsigned int uartclk); extern void serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old); extern void serial8250_do_set_ldisc(struct uart_port *port, -- 2.26.2