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