Hi

Here is patch for the driver for MPC8xx (SMC). If the idea is accepted
the then the driver for MPC82xx will be enhanced as well.

Best regards,
Stefan Bigler

diff --git a/cpu/mpc8xx/serial.c b/cpu/mpc8xx/serial.c
index ad02299..20440cd 100644
--- a/cpu/mpc8xx/serial.c
+++ b/cpu/mpc8xx/serial.c
@@ -108,17 +108,30 @@ static void smc_setbrg (void)
        serial_setdivisor(cp);
 }
 
+
+typedef volatile struct SerialBuffer { 
+       cbd_t rxbd;                                      /* Rx BD */
+       cbd_t txbd;                                              /* Tx
BD */
+#ifdef CONFIG_SMC_RXBUFLEN
+       uint  rxCharIndex;                           /* index for next
character to read */
+       volatile uchar rxbuf[CONFIG_SMC_RXBUFLEN];   /* rx buffers */
+#else
+       volatile uchar rxbuf[1];                     /* rx buffers */
+#endif
+       volatile uchar txbuf;                        /* tx buffers */
+} SerialBuffer;
+
 static int smc_init (void)
 {
        volatile immap_t *im = (immap_t *)CFG_IMMR;
        volatile smc_t *sp;
        volatile smc_uart_t *up;
-       volatile cbd_t *tbdf, *rbdf;
        volatile cpm8xx_t *cp = &(im->im_cpm);
 #if (!defined(CONFIG_8xx_CONS_SMC1)) && (defined(CONFIG_MPC823) ||
defined(CONFIG_MPC850))
        volatile iop8xx_t *ip = (iop8xx_t *)&(im->im_ioport);
 #endif
        uint    dpaddr;
+       SerialBuffer* rtx;
 
        /* initialize pointers to SMC */
 
@@ -194,23 +207,26 @@ static int smc_init (void)
         */
 
 #ifdef CFG_ALLOC_DPRAM
-       dpaddr = dpram_alloc_align (sizeof(cbd_t)*2 + 2, 8) ;
+       /* allocate 
+        * the size of struct SerialBuffer with bd rx/tx, buffer rx/tx
and rx index  
+        */
+       dpaddr = dpram_alloc_align ((sizeof(SerialBuffer)), 8);
 #else
        dpaddr = CPM_SERIAL_BASE ;
 #endif
 
+       rtx = (SerialBuffer*)&cp->cp_dpmem[dpaddr];
        /* Allocate space for two buffer descriptors in the DP ram.
         * For now, this address seems OK, but it may have to
         * change with newer versions of the firmware.
         * damm: allocating space after the two buffers for rx/tx data
         */
 
-       rbdf = (cbd_t *)&cp->cp_dpmem[dpaddr];
-       rbdf->cbd_bufaddr = (uint) (rbdf+2);
-       rbdf->cbd_sc = 0;
-       tbdf = rbdf + 1;
-       tbdf->cbd_bufaddr = ((uint) (rbdf+2)) + 1;
-       tbdf->cbd_sc = 0;
+       rtx->rxbd.cbd_bufaddr = (uint) &rtx->rxbuf;
+       rtx->rxbd.cbd_sc      = 0;
+
+       rtx->txbd.cbd_bufaddr = (uint) &rtx->txbuf;
+       rtx->txbd.cbd_sc      = 0;
 
        /* Set up the uart parameters in the parameter ram.
        */
@@ -256,13 +272,21 @@ static int smc_init (void)
 
        /* Make the first buffer the only buffer.
        */
-       tbdf->cbd_sc |= BD_SC_WRAP;
-       rbdf->cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
+       rtx->txbd.cbd_sc |= BD_SC_WRAP;
+       rtx->rxbd.cbd_sc |= BD_SC_EMPTY | BD_SC_WRAP;
 
+#ifdef CONFIG_SMC_RXBUFLEN
+       /* multi-character receive.
+       */
+       up->smc_mrblr    = CONFIG_SMC_RXBUFLEN;
+       up->smc_maxidl   = 10;
+       rtx->rxCharIndex = 0;
+#else 
        /* Single character receive.
        */
        up->smc_mrblr = 1;
        up->smc_maxidl = 0;
+#endif
 
        /* Initialize Tx/Rx parameters.
        */
@@ -285,11 +309,16 @@ static int smc_init (void)
 static void
 smc_putc(const char c)
 {
-       volatile cbd_t          *tbdf;
-       volatile char           *buf;
        volatile smc_uart_t     *up;
        volatile immap_t        *im = (immap_t *)CFG_IMMR;
        volatile cpm8xx_t       *cpmp = &(im->im_cpm);
+       SerialBuffer            *rtx;
+
+       up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
+#ifdef CFG_SMC_UCODE_PATCH
+       up = (smc_uart_t *)&cpmp->cp_dpmem[up->smc_rpbase];
+#endif
+       rtx = (SerialBuffer *)&cpmp->cp_dpmem[up->smc_rbase];
 
 #ifdef CONFIG_MODEM_SUPPORT
        if (gd->be_quiet)
@@ -299,24 +328,12 @@ smc_putc(const char c)
        if (c == '\n')
                smc_putc ('\r');
 
-       up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
-#ifdef CFG_SMC_UCODE_PATCH
-       up = (smc_uart_t *) &cpmp->cp_dpmem[up->smc_rpbase];
-#endif
-
-       tbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_tbase];
-
-       /* Wait for last character to go.
-       */
-
-       buf = (char *)tbdf->cbd_bufaddr;
-
-       *buf = c;
-       tbdf->cbd_datlen = 1;
-       tbdf->cbd_sc |= BD_SC_READY;
+       rtx->txbuf = c;
+       rtx->txbd.cbd_datlen = 1;
+       rtx->txbd.cbd_sc |= BD_SC_READY;
        __asm__("eieio");
 
-       while (tbdf->cbd_sc & BD_SC_READY) {
+       while (rtx->txbd.cbd_sc & BD_SC_READY) {
                WATCHDOG_RESET ();
                __asm__("eieio");
        }
@@ -333,29 +350,39 @@ smc_puts (const char *s)
 static int
 smc_getc(void)
 {
-       volatile cbd_t          *rbdf;
-       volatile unsigned char  *buf;
        volatile smc_uart_t     *up;
        volatile immap_t        *im = (immap_t *)CFG_IMMR;
        volatile cpm8xx_t       *cpmp = &(im->im_cpm);
-       unsigned char           c;
+       SerialBuffer            *rtx;
 
        up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
 #ifdef CFG_SMC_UCODE_PATCH
        up = (smc_uart_t *) &cpmp->cp_dpmem[up->smc_rpbase];
 #endif
 
-       rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+    rtx = (SerialBuffer *)&cpmp->cp_dpmem[up->smc_rbase];
+       unsigned char  c;
 
        /* Wait for character to show up.
        */
-       buf = (unsigned char *)rbdf->cbd_bufaddr;
-
-       while (rbdf->cbd_sc & BD_SC_EMPTY)
+       while (rtx->rxbd.cbd_sc & BD_SC_EMPTY)
                WATCHDOG_RESET ();
 
-       c = *buf;
-       rbdf->cbd_sc |= BD_SC_EMPTY;
+#ifdef CONFIG_SMC_RXBUFLEN
+       /* the characters are read one by one, use the rxCharIndex to
know the next char to deliver */
+       c = *(unsigned char *) (rtx->rxbd.cbd_bufaddr+rtx->rxCharIndex);
+       rtx->rxCharIndex++;
+
+       /* check if all char are readout, then make prepare for next
receive */
+       if (rtx->rxCharIndex >= rtx->rxbd.cbd_datlen)
+       {
+               rtx->rxCharIndex  = 0;
+       rtx->rxbd.cbd_sc |= BD_SC_EMPTY;
+       }
+#else
+       c = *(unsigned char *) (rtx->rxbd.cbd_bufaddr);
+       rtx->rxbd.cbd_sc |= BD_SC_EMPTY;
+#endif
 
        return(c);
 }
@@ -363,19 +390,19 @@ smc_getc(void)
 static int
 smc_tstc(void)
 {
-       volatile cbd_t          *rbdf;
        volatile smc_uart_t     *up;
        volatile immap_t        *im = (immap_t *)CFG_IMMR;
        volatile cpm8xx_t       *cpmp = &(im->im_cpm);
+       SerialBuffer            *rtx;
 
        up = (smc_uart_t *)&cpmp->cp_dparam[PROFF_SMC];
 #ifdef CFG_SMC_UCODE_PATCH
        up = (smc_uart_t *) &cpmp->cp_dpmem[up->smc_rpbase];
 #endif
 
-       rbdf = (cbd_t *)&cpmp->cp_dpmem[up->smc_rbase];
+       rtx = (SerialBuffer *)&cpmp->cp_dpmem[up->smc_rbase];
 
-       return(!(rbdf->cbd_sc & BD_SC_EMPTY));
+       return(!(rtx->rxbd.cbd_sc & BD_SC_EMPTY));
 }
 
 struct serial_device serial_smc_device =


> -----Original Message-----
> From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED]
> On Behalf Of Bigler, Stefan
> Sent: Wednesday, October 29, 2008 9:27 AM
> To: u-boot@lists.denx.de
> Subject: [U-Boot] RFC - How to speed up multiplexed input between
serial
> andnetwork?
> 
> Hi
> 
> We are trying to use U-Boot that it can be remote controlled over
> netconsole and in locally over the serial terminal.
> We were quite successful but we saw some latency issues on the serial
> terminal. The polling of the serial driver is too slow to get all
> characters. This does not allow you to e.g. to copy/paste, most of the
> characters are lost.
> 
> We analyzed the code and tried to speed it up, without the required
> improvement.
> The tests are done with an [EMAIL PROTECTED] and an MPC8247.
> 
> In the file common/console.c we added hooks to measure the time for
> tstc() execution.
> The measured time are:
> serial-driver     3 Microseconds
> nc                 15 Milliseconds
> 
> The result is, that the serial interface is polled only every 15
> Millisecond.
> On the serial interface with a line-rate of 115200 we receive aprox
> 10'000 Character every second. This is one character every 100
> Microsecond.
> 
> The serial driver has one buffer-descriptor with the space for one
> character. This results in a maximal polling period of 100
Microseconds.
> 
> The HW-FIFO for a MPC852T is 2 bytes.
> 
> 
> There are 2 possibilities to solve the problem:
> -----------------------------------------------
> a) make the netconsole faster
> b) make serial more "robust" and allow more latency
> 
> The better solution is of course to make the netconsole faster. But
can
> we reach 100 Microseconds?
> We can reduce it (as already done e.g. accelerate the readout of
> env-variables). To accelerate by factor 150 we need to do major
changes
> e.g. read-out the env if changed so we need a mechanism to see this.
> 
> On the other hand we can enhance the serial driver to "absorb" e.g.
one
> line that allows you to copy/paste.
> This is not a big code change but it needs more dp-ram.
> 
> The copy/paste test shows the following result
> copy          paste
> 0123456789 -> 0 -> first character
> 
> 
> a) So I tried to make the netconsole faster with the optimisation of
> tstc()
>
------------------------------------------------------------------------
> ---
> There is the possibility to do the getenv() only if the env is
changed.
> I added a "transactionId" what is incremented after every write to
env.
> So the user of env can check if the env changed and only read if
> changed.
> This reduced the tstc() of nc to 60 Microseconds. So the polling of
> serial is done every 70 Microseconds.
> In principle this should be fast enough to be able to copy paste
> copy          paste
> 0123456789 -> 013679 -> 50%
> 
> Why are we receiving only half of the character? This due to the fact
> that processing a character needs time. If we check how often we call
> getc() while copy/paste, this is every 180 Microsecond. The method
> getc() do not need lot of time, but the received character is sent
over
> nc before we get the next char. I think we cannot avoid this.
> 
> I do not see how we can reduce this time even further.
> 
> The measurement is also done without nc. There the getc() is called
> every 80-90 Microseconds. So we see that is little headroom to do
> additional processing!
> 
> 
> b) Make the serial driver more "robust" to absorb bursts
> --------------------------------------------------------
> I think it would make sense to be able to absorb the burst of one line
> e.g. 128 character.
> 
> This can be done in 2 way:
> b1) use more buffer descriptor with one character
> b2) use the feature of smc to allow multi-character buffer
> 
> b1) driver with multi buffer descriptor
> ---------------------------------------
> This is the possibility that is quite simple to implement, but needs
> more resources. I have already sent this. The required
dual-port-memory
> is high
> 128 bd * 8 byte plus 128 byte for character = 1152 byte more.
> (I also implemented this driver)
> 
> b2) driver with multi-character buffer
> --------------------------------------
> I have implemented this driver for MPC852T (SMC) and attached a patch.
> The additional use of DP-RAM is the size the buffer (e.g. 128 bytes)
and
> 4 bytes for an index to the next character to read.
> A define can be used to specify the size of the buffer. If undefined
the
> size is 1.
> 
> 
> Conclusion:
> -----------
> I do not see a good chance to be able to reduce the processing time in
> the netconsole below 100 Microseconds.
> 
> I expect copy/paste to work for a line (128 characters).
> 
> So I propose to enhance the serial driver.
> 
> Best regards,
> Stefan Bigler
> 
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
> 

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to