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: [email protected]
> 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
> [email protected]
> http://lists.denx.de/mailman/listinfo/u-boot
>
_______________________________________________
U-Boot mailing list
[email protected]
http://lists.denx.de/mailman/listinfo/u-boot