Received: by 2002:a05:6902:102b:0:0:0:0 with SMTP id x11csp921562ybt; Fri, 10 Jul 2020 16:18:35 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyUFbXEiA38YNNZA4R89IwETrjkyOyxqBydi5a7l8CawQW1r/m7YFq9pA3tTF7CFv6itwar X-Received: by 2002:a50:8749:: with SMTP id 9mr677349edv.80.1594423115428; Fri, 10 Jul 2020 16:18:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1594423115; cv=none; d=google.com; s=arc-20160816; b=w7qaX1AOXOuG9yKWUa2V+tK5hcKySlaSXSZ/CDHdzuaiv0ldCbv1J38srZQroln7wE rSwH9OLGbp/ym3sMuyOHnj/kyonK06CXZgwpvvqErar9+YvSdqLh81P5hjNxHq+ggk0x Uu7nCO/WW7ehsvjkPDoudPDM3aopELvCbDvRAcviJwQKDy1xmutI+k581Yp1nAul9OeV 3R3MD0mDIEJGQ8pyFDl0ks+V6JpNe7X5dNHB64b+iCSPHQM3g5YJN5XNE0abfdtuYTsX mP5iNOTo70c3N0tG5TLvD0920lSyxnj9utKulukW3ie0W+WG685LVtDSVGGNcL2lI9xv bL/w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=WCmMFbtQRToohRjqaMphHVw3Hmc8aGOBEevW9jyCCdE=; b=Cl8R92QqVIg/ItdiCsHkFU1GOC6ZOhrhtdHGmBoCL28ubOmutL133l8EPFPMtrgZmm ORPkhqsCYAUG5aFlFj5yXZQK2eb4BHlwpZLDleyiEtbGJYqlzTzkmlG2XnaskHEnMHzV OzgPxtm3JVf7A2ffIEHpuzKx71ehwntix0ha0LAmD2ugteSys189uvZORmaKIC7Yt0Np b1LA8GaK7mOYNu8CA5vkPhEFN8Zd0ePqsBPwhf+j2amzotO6xkEUGMLX26edSn8Fq42z rHm7Ju7kQ3/3941TPOVjZg8CpARD1F6F9tg29xqCx4WJ6EeqNPL0gEDkDo2Cb4+kVNTJ 6dQg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=W78DQdbS; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id f16si4334852ejb.557.2020.07.10.16.18.11; Fri, 10 Jul 2020 16:18:35 -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; dkim=pass header.i=@chromium.org header.s=google header.b=W78DQdbS; 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; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726523AbgGJXPy (ORCPT + 99 others); Fri, 10 Jul 2020 19:15:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40758 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726519AbgGJXPx (ORCPT ); Fri, 10 Jul 2020 19:15:53 -0400 Received: from mail-lf1-x143.google.com (mail-lf1-x143.google.com [IPv6:2a00:1450:4864:20::143]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F001FC08C5DD for ; Fri, 10 Jul 2020 16:15:52 -0700 (PDT) Received: by mail-lf1-x143.google.com with SMTP id o4so4067751lfi.7 for ; Fri, 10 Jul 2020 16:15:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=WCmMFbtQRToohRjqaMphHVw3Hmc8aGOBEevW9jyCCdE=; b=W78DQdbSYS6X6wt7Yhf1uxkiVZT/5GHGMdIaP0it6nogqsD/+OXU8an49Fu0RDUILt y9vh+Tu5oW4y7jlylWFlJbH675Pn6b7kftzu4/TxOMZuX6xO9w6RVlQDePTB42G2NeZR xVY53lIGl3sCP4gdv90espr+N1rO39CVIN6+0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=WCmMFbtQRToohRjqaMphHVw3Hmc8aGOBEevW9jyCCdE=; b=NjE1L2RBPNVnpwTROuY0/SVsSDs5eO58zjz3L7aKOcKKRrlqrYXSf1n63ByQM9kJc6 hM3r5z25tuX1gwu2x8So6XjqFg083FNdoZQ34sL78ZvTP8ZsOdy7fP3VxlqOYofvIvEZ ACSpjgaHsat2O4B26KZnN9WHWcKFhMt0dISIfZQGV2NRTK3/CM1nxb0wms/VL04ci2r1 DrLlv+UmmLmh1lS4dAg5I6U9efueSr+Bm+eQUgo9EgTPkhKroN0P8yxoNcG6JyKEmi5L 2l8yNDxxQ8btL+aba4R6p0t9D51oJztU3d8HVihYcxEpzC/2/skYJ0VdK0T2/62UgBEd 9bbQ== X-Gm-Message-State: AOAM530pRktlrqROlIWAuuuthRuTpIlR/Y/5vHXsAtAhdJfGkfR0E2Dx yqj4DRNE1P4W2FCguIcsXhLoOC5IFW4= X-Received: by 2002:ac2:5f04:: with SMTP id 4mr44953945lfq.140.1594422950703; Fri, 10 Jul 2020 16:15:50 -0700 (PDT) Received: from mail-lj1-f170.google.com (mail-lj1-f170.google.com. [209.85.208.170]) by smtp.gmail.com with ESMTPSA id x24sm2363318ljh.21.2020.07.10.16.15.48 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 10 Jul 2020 16:15:49 -0700 (PDT) Received: by mail-lj1-f170.google.com with SMTP id h19so8163913ljg.13 for ; Fri, 10 Jul 2020 16:15:48 -0700 (PDT) X-Received: by 2002:a2e:2242:: with SMTP id i63mr43905141lji.370.1594422947888; Fri, 10 Jul 2020 16:15:47 -0700 (PDT) MIME-Version: 1.0 References: <20200626200033.1528052-1-dianders@chromium.org> <20200626125844.1.I8546ecb6c5beb054f70c5302d1a7293484212cd1@changeid> In-Reply-To: From: Evan Green Date: Fri, 10 Jul 2020 16:15:11 -0700 X-Gmail-Original-Message-ID: Message-ID: Subject: Re: [PATCH 1/2] serial: qcom_geni_serial: Make kgdb work even if UART isn't console To: Doug Anderson Cc: Greg Kroah-Hartman , Daniel Thompson , Akash Asthana , Stephen Boyd , kgdb-bugreport@lists.sourceforge.net, linux-arm-msm , Sumit Garg , Vivek Gautam , Andy Gross , Bjorn Andersson , Jiri Slaby , LKML , linux-serial@vger.kernel.org Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Fri, Jul 10, 2020 at 12:24 PM Doug Anderson wrote: > > Hi, > > On Fri, Jul 10, 2020 at 12:03 PM Evan Green wrote: > > > > On Fri, Jul 10, 2020 at 11:19 AM Doug Anderson wrote: > > > > > > Hi, > > > > > > On Fri, Jul 10, 2020 at 10:39 AM Evan Green wrote: > > > > > > > > On Fri, Jun 26, 2020 at 1:01 PM Douglas Anderson wrote: > > > > > > > > > > The geni serial driver had the rather sketchy hack in it where it > > > > > would adjust the number of bytes per RX FIFO word from 4 down to 1 if > > > > > it detected that CONFIG_CONSOLE_POLL was enabled (for kgdb) and this > > > > > was a console port (defined by the kernel directing output to this > > > > > port via the "console=" command line argument). > > > > > > > > > > The problem with that sketchy hack is that it's possible to run kgdb > > > > > over a serial port even if it isn't used for console. > > > > > > > > > > Let's avoid the hack by simply handling the 4-bytes-per-FIFO word case > > > > > for kdb. We'll have to have a (very small) cache but that should be > > > > > fine. > > > > > > > > > > A nice side effect of this patch is that an agetty (or similar) > > > > > running on this port is less likely to drop characters. We'll > > > > > have roughly 4 times the RX FIFO depth than we used to now. > > > > > > > > > > NOTE: the character cache here isn't shared between the polling API > > > > > and the non-polling API. That means that, technically, the polling > > > > > API could eat a few extra bytes. This doesn't seem to pose a huge > > > > > problem in reality because we'll only get several characters per FIFO > > > > > word if those characters are all received at nearly the same time and > > > > > we don't really expect non-kgdb characters to be sent to the same port > > > > > as kgdb at the exact same time we're exiting kgdb. > > > > > > > > > > ALSO NOTE: we still have the sketchy hack for setting the number of > > > > > bytes per TX FIFO word in place, but that one is less bad. kgdb > > > > > doesn't have any problem with this because it always just sends 1 byte > > > > > at a time and waits for it to finish. The TX FIFO hack is only really > > > > > needed for console output. In any case, a future patch will remove > > > > > that hack, too. > > > > > > > > > > Signed-off-by: Douglas Anderson > > > > > --- > > > > > > > > > > drivers/tty/serial/qcom_geni_serial.c | 80 ++++++++++++++++++--------- > > > > > 1 file changed, 55 insertions(+), 25 deletions(-) > > > > > > > > > > diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c > > > > > index 0300867eab7a..4610e391e886 100644 > > > > > --- a/drivers/tty/serial/qcom_geni_serial.c > > > > > +++ b/drivers/tty/serial/qcom_geni_serial.c > > > > > @@ -103,11 +103,13 @@ > > > > > #define DEFAULT_IO_MACRO_IO2_IO3_MASK GENMASK(15, 4) > > > > > #define IO_MACRO_IO2_IO3_SWAP 0x4640 > > > > > > > > > > -#ifdef CONFIG_CONSOLE_POLL > > > > > -#define CONSOLE_RX_BYTES_PW 1 > > > > > -#else > > > > > -#define CONSOLE_RX_BYTES_PW 4 > > > > > -#endif > > > > > +struct qcom_geni_private_data { > > > > > + /* NOTE: earlycon port will have NULL here */ > > > > > + struct uart_driver *drv; > > > > > + > > > > > + u32 poll_cached_bytes; > > > > > + unsigned int poll_cached_bytes_cnt; > > > > > +}; > > > > > > > > > > struct qcom_geni_serial_port { > > > > > struct uart_port uport; > > > > > @@ -129,6 +131,8 @@ struct qcom_geni_serial_port { > > > > > int wakeup_irq; > > > > > bool rx_tx_swap; > > > > > bool cts_rts_swap; > > > > > + > > > > > + struct qcom_geni_private_data private_data; > > > > > }; > > > > > > > > > > static const struct uart_ops qcom_geni_console_pops; > > > > > @@ -264,8 +268,9 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport, > > > > > unsigned int baud; > > > > > unsigned int fifo_bits; > > > > > unsigned long timeout_us = 20000; > > > > > + struct qcom_geni_private_data *private_data = uport->private_data; > > > > > > > > > > - if (uport->private_data) { > > > > > + if (private_data->drv) { > > > > > port = to_dev_port(uport, uport); > > > > > baud = port->baud; > > > > > if (!baud) > > > > > @@ -331,23 +336,42 @@ static void qcom_geni_serial_abort_rx(struct uart_port *uport) > > > > > } > > > > > > > > > > #ifdef CONFIG_CONSOLE_POLL > > > > > + > > > > > static int qcom_geni_serial_get_char(struct uart_port *uport) > > > > > { > > > > > - u32 rx_fifo; > > > > > + struct qcom_geni_private_data *private_data = uport->private_data; > > > > > u32 status; > > > > > + u32 word_cnt; > > > > > + int ret; > > > > > + > > > > > + if (!private_data->poll_cached_bytes_cnt) { > > > > > + status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); > > > > > + writel(status, uport->membase + SE_GENI_M_IRQ_CLEAR); > > > > > > > > > > - status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); > > > > > - writel(status, uport->membase + SE_GENI_M_IRQ_CLEAR); > > > > > + status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); > > > > > + writel(status, uport->membase + SE_GENI_S_IRQ_CLEAR); > > > > > > > > > > - status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); > > > > > - writel(status, uport->membase + SE_GENI_S_IRQ_CLEAR); > > > > > + status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS); > > > > > + word_cnt = status & RX_FIFO_WC_MSK; > > > > > + if (!word_cnt) > > > > > + return NO_POLL_CHAR; > > > > > > > > > > - status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS); > > > > > - if (!(status & RX_FIFO_WC_MSK)) > > > > > - return NO_POLL_CHAR; > > > > > + if (word_cnt == 1 && (status & RX_LAST)) > > > > > > > > I forget how the partial word snapping works. Are you sure you want > > > > word_cnt == 1? I see qcom_geni_serial_handle_rx() looks at RX_LAST > > > > independently as long as word_cnt != 0. I'm worried the hardware > > > > allows one FIFO entry with say 2 bytes in it and RX_LAST set, but then > > > > also piles new stuff in the FIFO behind it, so that word_cnt can be > > > > >1. > > > > > > So I guess one point of evidence that the logic I have there is OK is > > > that it works. :-P > > > > > > ...but also looking closer. Maybe first it's important to understand > > > the REALLY WEIRD protocol that geni serial uses. This was discovered > > > through a bunch of trial and error long ago when poking at how the > > > driver worked. > > > > > > When you're reading from geni it essentially breaks things into > > > packets. If you're midway through reading a packet of data and more > > > bytes come in then geni will hide them from you until you read the > > > whole packet. I'm not totally sure the exact conditions for when it > > > decides to make a packet out of the data, but it's not important for > > > this discussion. > > > > > > So when you read "RX_FIFO_WC" it tells you the total number of FIFO > > > words in the current packet. That number will only ever go down. A > > > packet is made up of some number of whole words plus one word that > > > could be a whole word or could be a partial word. So if "RX_FIFO_WC" > > > says 4 it means you've got 3 whole words (3 * 4 = 12 bytes) and one > > > word that might be partial. You can find out about that one partial > > > word (always the last word in the FIFO) by reading "RX_LAST" and > > > "RX_LAST_BYTE_VALID". > > > > > > Once you finally read the last word in the FIFO then geni can tell you > > > about the next packet of data. > > > > > > OK, so hopefully that made sense? > > > > I see, yes. In your description, the status register is a single > > storage element with a decrementing counter that stores the state for > > this current packet. Then it's a mystery how/where additional packets > > are buffered. > > > > In my mental model, RX_FIFO_WC tells you how many elements are > > occupied in the FIFO, regardless of packet boundaries. RX_LAST and > > byte count are actually little tags in each FIFO element. So a FIFO > > element internally consists of 4 data bytes + 3 status bits. Then that > > portion of the status register shows you the status/tag bits for the > > element at the top of the FIFO. I can't remember why I think it works > > this way, but it does explain how the hardware can queue/store > > multiple RX packets, and how it would handle overflows. > > > > > > > > So qcom_geni_serial_handle_rx() is trying to read ALL bytes. It first > > > figures out the total count of bytes and then reads them all. That's > > > why it needs to look at RX_LAST all the time. Also of note: RX_LAST > > > only ever applies to the last word in the FIFO. If it was possible > > > for the word count to grow _before_ fully clearing out the FIFO then > > > it would be a race and software would never be able to tell which byte > > > RX_LAST applied to. > > > > In my world, I was imagining word count could grow, since it showed > > the current fullness of the FIFO, but RX_LAST and BYTE_COUNT_MSK > > showed the tag bits for the current element. It looked like > > qcom_geni_serial_handle_rx() was coded for that since it seemed to > > only check that FIFO_WC was non-zero. > > Ah, but look at how the ->handle_rx() call works. Specifically let's > look at handle_rx_console(). It takes in a count and just reads > everything without referring back to RX_LAST and RX_LAST_BYTE_VALID. > If your model was the one geni was actually using then wouldn't that > call need to be re-checking RX_LAST and RX_LAST_BYTE_VALID for each > FIFO entry? You can see that as it's reading from the FIFO it reads > all whole words first and then only reads a partial word for the very > last word in the packet. Ah yep, I see that. That definitely confirms your model over mine. Deducing peripheral behavior based on driver implementation is fun and easy :) Thanks for taking the time to explain it to me. Reviewed-by: Evan Green