From patchwork Mon Dec 14 18:57:21 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Geert Uytterhoeven X-Patchwork-Id: 7846911 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: X-Original-To: patchwork-linux-sh@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 86ED79F3CD for ; Mon, 14 Dec 2015 18:58:09 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A960C20386 for ; Mon, 14 Dec 2015 18:58:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C47FF20382 for ; Mon, 14 Dec 2015 18:58:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932170AbbLNS6F (ORCPT ); Mon, 14 Dec 2015 13:58:05 -0500 Received: from baptiste.telenet-ops.be ([195.130.132.51]:45344 "EHLO baptiste.telenet-ops.be" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932180AbbLNS5r (ORCPT ); Mon, 14 Dec 2015 13:57:47 -0500 Received: from ayla.of.borg ([84.195.106.123]) by baptiste.telenet-ops.be with bizsmtp id tWxi1r0122fm56U01WxiaQ; Mon, 14 Dec 2015 19:57:43 +0100 Received: from ramsan.of.borg ([192.168.97.29] helo=ramsan) by ayla.of.borg with esmtp (Exim 4.82) (envelope-from ) id 1a8YJa-0002tl-6I; Mon, 14 Dec 2015 19:57:42 +0100 Received: from geert by ramsan with local (Exim 4.82) (envelope-from ) id 1a8YJd-0000HY-Kd; Mon, 14 Dec 2015 19:57:45 +0100 From: Geert Uytterhoeven To: Greg Kroah-Hartman , Simon Horman , Magnus Damm , Yoshinori Sato Cc: linux-serial@vger.kernel.org, linux-sh@vger.kernel.org, Geert Uytterhoeven Subject: [PATCH v3 12/27] serial: sh-sci: Avoid overflow in sci_baud_calc_hscif() Date: Mon, 14 Dec 2015 19:57:21 +0100 Message-Id: <1450119456-964-13-git-send-email-geert+renesas@glider.be> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1450119456-964-1-git-send-email-geert+renesas@glider.be> References: <1450119456-964-1-git-send-email-geert+renesas@glider.be> Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP If bps >= 1048576, the multiplication of the predivider and "bps" will overflow, and both br and err will contain bogus values. Skip the current and all higher clock select predividers when overflow is detected. Simplify the calculations using intermediates while we're at it. Signed-off-by: Geert Uytterhoeven Acked-by: Greg Kroah-Hartman --- v3: - Add Acked-by, - Rename intermediates to "prediv" and "scrate", - Add a comment explaining the calculation and possible overflow. --- drivers/tty/serial/sh-sci.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 77e0a582da44947f..c490c51d6032786b 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1870,7 +1870,7 @@ static unsigned int sci_scbrr_calc(struct sci_port *s, unsigned int bps, static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, int *brr, unsigned int *srr, unsigned int *cks) { - unsigned int sr, br, c; + unsigned int sr, br, prediv, scrate, c; int err, recv_margin; int min_err = 1000; /* 100% */ int recv_max_margin = 0; @@ -1880,12 +1880,25 @@ static void sci_baud_calc_hscif(unsigned int bps, unsigned long freq, int *brr, for (sr = 8; sr <= 32; sr++) { for (c = 0; c <= 3; c++) { /* integerized formulas from HSCIF documentation */ - br = DIV_ROUND_CLOSEST(freq, (sr * - (1 << (2 * c + 1)) * bps)); + prediv = sr * (1 << (2 * c + 1)); + + /* + * We need to calculate: + * + * br = freq / (prediv * bps) clamped to [1..256] + * err = (freq / (br * prediv * bps / 1000)) - 1000 + * + * Watch out for overflow when calculating the desired + * sampling clock rate! + */ + if (bps > UINT_MAX / prediv) + break; + + scrate = prediv * bps; + br = DIV_ROUND_CLOSEST(freq, scrate); br = clamp(br, 1U, 256U); - err = DIV_ROUND_CLOSEST(freq, (br * bps * sr * - (1 << (2 * c + 1)) / 1000)) - - 1000; + err = DIV_ROUND_CLOSEST(freq, (br * scrate) / 1000) - + 1000; /* Calc recv margin * M: Receive margin (%) * N: Ratio of bit rate to clock (N = sampling rate)