Re: [PATCH v2 1/1] bsps/i386: Update calibration of TSC to be more accurate
I'm good with it for master and 5. On Wed, Jun 16, 2021 at 4:18 AM Jan Sommer wrote: > > Closes #4455 > --- > bsps/i386/pc386/clock/ckinit.c | 71 ++ > 1 file changed, 38 insertions(+), 33 deletions(-) > > diff --git a/bsps/i386/pc386/clock/ckinit.c b/bsps/i386/pc386/clock/ckinit.c > index 09afe73cde..2df1818dd3 100644 > --- a/bsps/i386/pc386/clock/ckinit.c > +++ b/bsps/i386/pc386/clock/ckinit.c > @@ -104,48 +104,60 @@ static uint32_t pc386_get_timecount_i8254(struct > timecounter *tc) > > /* > * Calibrate CPU cycles per tick. Interrupts should be disabled. > + * Will also set the PIT, so call this before registering the > + * periodic timer for rtems tick generation > */ > static void calibrate_tsc(void) > { >uint64_t begin_time; > - uint8_t then_lsb, then_msb, now_lsb, now_msb; > - uint32_t i; > - > - /* > - * We just reset the timer, so we know we're at the beginning of a tick. > - */ > - > - /* > - * Count cycles. Watching the timer introduces a several microsecond > - * uncertaintity, so let it cook for a while and divide by the number of > - * ticks actually executed. > - */ > + uint8_t lsb, msb; > + uint32_t max_timer_value; > + uint32_t last_tick, cur_tick; > + int32_t diff, remaining; > + > + /* Set the timer to free running mode */ > + outport_byte(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_INTTC); > + /* Reset the 16 timer reload value, first LSB, then MSB */ > + outport_byte(TIMER_CNTR0, 0); > + outport_byte(TIMER_CNTR0, 0); > + /* We use the full 16 bit */ > + max_timer_value = 0x; > + /* Calibrate for 1s, i.e. TIMER_TICK PIT ticks */ > + remaining = TIMER_TICK; > >begin_time = rdtsc(); > - > - for (i = rtems_clock_get_ticks_per_second() * pc386_isrs_per_tick; > - i != 0; --i ) { > -/* We know we've just completed a tick when timer goes from low to high > */ > -then_lsb = then_msb = 0xff; > -do { > - READ_8254(now_lsb, now_msb); > - if ((then_msb < now_msb) || > - ((then_msb == now_msb) && (then_lsb < now_lsb))) > -break; > - then_lsb = now_lsb; > - then_msb = now_msb; > -} while (1); > + READ_8254(lsb, msb); > + last_tick = (msb << 8) | lsb; > + while(remaining > 0) { > +READ_8254(lsb, msb); > +cur_tick = (msb << 8) | lsb; > +/* PIT counts down, so subtract cur from last */ > +diff = last_tick - cur_tick; > +last_tick = cur_tick; > +if (diff < 0) { > +diff += max_timer_value; > +} > +remaining -= diff; >} > >pc586_tsc_frequency = rdtsc() - begin_time; > > #if 0 > - printk( "CPU clock at %u MHz\n", (uint32_t)(pc586_tsc_frequency / > 100)); > + printk( "CPU clock at %u Hz\n", (uint32_t)(pc586_tsc_frequency )); > #endif > } > > static void clockOn(void) > { > + > + /* > + * First calibrate the TSC. Do this every time we > + * turn the clock on in case the CPU clock speed has changed. > + */ > + if ( x86_has_tsc() ) { > +calibrate_tsc(); > + } > + >rtems_interrupt_lock_context lock_context; >pc386_isrs_per_tick= 1; >pc386_microseconds_per_isr = > rtems_configuration_get_microseconds_per_tick(); > @@ -171,13 +183,6 @@ static void clockOn(void) >rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context); > >bsp_interrupt_vector_enable( BSP_PERIODIC_TIMER ); > - > - /* > - * Now calibrate cycles per tick. Do this every time we > - * turn the clock on in case the CPU clock speed has changed. > - */ > - if ( x86_has_tsc() ) > -calibrate_tsc(); > } > > bool Clock_isr_enabled = false; > -- > 2.17.1 > > ___ > devel mailing list > devel@rtems.org > http://lists.rtems.org/mailman/listinfo/devel ___ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel
Re: [PATCH v2 1/1] bsps/i386: Update calibration of TSC to be more accurate
Me too. Just needs separate tickets for 5 and 6 so the release notes are generated correctly. On Wed, Jun 16, 2021 at 12:51 PM Gedare Bloom wrote: > I'm good with it for master and 5. > > On Wed, Jun 16, 2021 at 4:18 AM Jan Sommer wrote: > > > > Closes #4455 > > --- > > bsps/i386/pc386/clock/ckinit.c | 71 ++ > > 1 file changed, 38 insertions(+), 33 deletions(-) > > > > diff --git a/bsps/i386/pc386/clock/ckinit.c > b/bsps/i386/pc386/clock/ckinit.c > > index 09afe73cde..2df1818dd3 100644 > > --- a/bsps/i386/pc386/clock/ckinit.c > > +++ b/bsps/i386/pc386/clock/ckinit.c > > @@ -104,48 +104,60 @@ static uint32_t pc386_get_timecount_i8254(struct > timecounter *tc) > > > > /* > > * Calibrate CPU cycles per tick. Interrupts should be disabled. > > + * Will also set the PIT, so call this before registering the > > + * periodic timer for rtems tick generation > > */ > > static void calibrate_tsc(void) > > { > >uint64_t begin_time; > > - uint8_t then_lsb, then_msb, now_lsb, now_msb; > > - uint32_t i; > > - > > - /* > > - * We just reset the timer, so we know we're at the beginning of a > tick. > > - */ > > - > > - /* > > - * Count cycles. Watching the timer introduces a several microsecond > > - * uncertaintity, so let it cook for a while and divide by the number > of > > - * ticks actually executed. > > - */ > > + uint8_t lsb, msb; > > + uint32_t max_timer_value; > > + uint32_t last_tick, cur_tick; > > + int32_t diff, remaining; > > + > > + /* Set the timer to free running mode */ > > + outport_byte(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_INTTC); > > + /* Reset the 16 timer reload value, first LSB, then MSB */ > > + outport_byte(TIMER_CNTR0, 0); > > + outport_byte(TIMER_CNTR0, 0); > > + /* We use the full 16 bit */ > > + max_timer_value = 0x; > > + /* Calibrate for 1s, i.e. TIMER_TICK PIT ticks */ > > + remaining = TIMER_TICK; > > > >begin_time = rdtsc(); > > - > > - for (i = rtems_clock_get_ticks_per_second() * pc386_isrs_per_tick; > > - i != 0; --i ) { > > -/* We know we've just completed a tick when timer goes from low to > high */ > > -then_lsb = then_msb = 0xff; > > -do { > > - READ_8254(now_lsb, now_msb); > > - if ((then_msb < now_msb) || > > - ((then_msb == now_msb) && (then_lsb < now_lsb))) > > -break; > > - then_lsb = now_lsb; > > - then_msb = now_msb; > > -} while (1); > > + READ_8254(lsb, msb); > > + last_tick = (msb << 8) | lsb; > > + while(remaining > 0) { > > +READ_8254(lsb, msb); > > +cur_tick = (msb << 8) | lsb; > > +/* PIT counts down, so subtract cur from last */ > > +diff = last_tick - cur_tick; > > +last_tick = cur_tick; > > +if (diff < 0) { > > +diff += max_timer_value; > > +} > > +remaining -= diff; > >} > > > >pc586_tsc_frequency = rdtsc() - begin_time; > > > > #if 0 > > - printk( "CPU clock at %u MHz\n", (uint32_t)(pc586_tsc_frequency / > 100)); > > + printk( "CPU clock at %u Hz\n", (uint32_t)(pc586_tsc_frequency )); > > #endif > > } > > > > static void clockOn(void) > > { > > + > > + /* > > + * First calibrate the TSC. Do this every time we > > + * turn the clock on in case the CPU clock speed has changed. > > + */ > > + if ( x86_has_tsc() ) { > > +calibrate_tsc(); > > + } > > + > >rtems_interrupt_lock_context lock_context; > >pc386_isrs_per_tick= 1; > >pc386_microseconds_per_isr = > rtems_configuration_get_microseconds_per_tick(); > > @@ -171,13 +183,6 @@ static void clockOn(void) > >rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, > &lock_context); > > > >bsp_interrupt_vector_enable( BSP_PERIODIC_TIMER ); > > - > > - /* > > - * Now calibrate cycles per tick. Do this every time we > > - * turn the clock on in case the CPU clock speed has changed. > > - */ > > - if ( x86_has_tsc() ) > > -calibrate_tsc(); > > } > > > > bool Clock_isr_enabled = false; > > -- > > 2.17.1 > > > > ___ > > devel mailing list > > devel@rtems.org > > http://lists.rtems.org/mailman/listinfo/devel > ___ > devel mailing list > devel@rtems.org > http://lists.rtems.org/mailman/listinfo/devel > ___ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel
RE: [PATCH v2 1/1] bsps/i386: Update calibration of TSC to be more accurate
Thanks, I prepared tickets for master and 5. I will make sure that the link in the commit message fits the right ticket of the corresponding branch. My plan is to push that on Monday, when I am back in the office Best regards, Jan From: Joel Sherrill Sent: Wednesday, June 16, 2021 8:06 PM To: Gedare Bloom Cc: Sommer, Jan ; devel@rtems.org Subject: Re: [PATCH v2 1/1] bsps/i386: Update calibration of TSC to be more accurate Me too. Just needs separate tickets for 5 and 6 so the release notes are generated correctly. On Wed, Jun 16, 2021 at 12:51 PM Gedare Bloom mailto:ged...@rtems.org>> wrote: I'm good with it for master and 5. On Wed, Jun 16, 2021 at 4:18 AM Jan Sommer mailto:jan.som...@dlr.de>> wrote: > > Closes #4455 > --- > bsps/i386/pc386/clock/ckinit.c | 71 ++ > 1 file changed, 38 insertions(+), 33 deletions(-) > > diff --git a/bsps/i386/pc386/clock/ckinit.c b/bsps/i386/pc386/clock/ckinit.c > index 09afe73cde..2df1818dd3 100644 > --- a/bsps/i386/pc386/clock/ckinit.c > +++ b/bsps/i386/pc386/clock/ckinit.c > @@ -104,48 +104,60 @@ static uint32_t pc386_get_timecount_i8254(struct > timecounter *tc) > > /* > * Calibrate CPU cycles per tick. Interrupts should be disabled. > + * Will also set the PIT, so call this before registering the > + * periodic timer for rtems tick generation > */ > static void calibrate_tsc(void) > { >uint64_t begin_time; > - uint8_t then_lsb, then_msb, now_lsb, now_msb; > - uint32_t i; > - > - /* > - * We just reset the timer, so we know we're at the beginning of a tick. > - */ > - > - /* > - * Count cycles. Watching the timer introduces a several microsecond > - * uncertaintity, so let it cook for a while and divide by the number of > - * ticks actually executed. > - */ > + uint8_t lsb, msb; > + uint32_t max_timer_value; > + uint32_t last_tick, cur_tick; > + int32_t diff, remaining; > + > + /* Set the timer to free running mode */ > + outport_byte(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_INTTC); > + /* Reset the 16 timer reload value, first LSB, then MSB */ > + outport_byte(TIMER_CNTR0, 0); > + outport_byte(TIMER_CNTR0, 0); > + /* We use the full 16 bit */ > + max_timer_value = 0x; > + /* Calibrate for 1s, i.e. TIMER_TICK PIT ticks */ > + remaining = TIMER_TICK; > >begin_time = rdtsc(); > - > - for (i = rtems_clock_get_ticks_per_second() * pc386_isrs_per_tick; > - i != 0; --i ) { > -/* We know we've just completed a tick when timer goes from low to high > */ > -then_lsb = then_msb = 0xff; > -do { > - READ_8254(now_lsb, now_msb); > - if ((then_msb < now_msb) || > - ((then_msb == now_msb) && (then_lsb < now_lsb))) > -break; > - then_lsb = now_lsb; > - then_msb = now_msb; > -} while (1); > + READ_8254(lsb, msb); > + last_tick = (msb << 8) | lsb; > + while(remaining > 0) { > +READ_8254(lsb, msb); > +cur_tick = (msb << 8) | lsb; > +/* PIT counts down, so subtract cur from last */ > +diff = last_tick - cur_tick; > +last_tick = cur_tick; > +if (diff < 0) { > +diff += max_timer_value; > +} > +remaining -= diff; >} > >pc586_tsc_frequency = rdtsc() - begin_time; > > #if 0 > - printk( "CPU clock at %u MHz\n", (uint32_t)(pc586_tsc_frequency / > 100)); > + printk( "CPU clock at %u Hz\n", (uint32_t)(pc586_tsc_frequency )); > #endif > } > > static void clockOn(void) > { > + > + /* > + * First calibrate the TSC. Do this every time we > + * turn the clock on in case the CPU clock speed has changed. > + */ > + if ( x86_has_tsc() ) { > +calibrate_tsc(); > + } > + >rtems_interrupt_lock_context lock_context; >pc386_isrs_per_tick= 1; >pc386_microseconds_per_isr = > rtems_configuration_get_microseconds_per_tick(); > @@ -171,13 +183,6 @@ static void clockOn(void) >rtems_interrupt_lock_release(&rtems_i386_i8254_access_lock, &lock_context); > >bsp_interrupt_vector_enable( BSP_PERIODIC_TIMER ); > - > - /* > - * Now calibrate cycles per tick. Do this every time we > - * turn the clock on in case the CPU clock speed has changed. > - */ > - if ( x86_has_tsc() ) > -calibrate_tsc(); > } > > bool Clock_isr_enabled = false; > -- > 2.17.1 > > ___ > devel mailing list > devel@rtems.org<mailto:devel@rtems.org> > http://lists.rtems.org/mailman/listinfo/devel ___ devel mailing list devel@rtems.org<mailto:devel@rtems.org> http://lists.rtems.org/mailman/listinfo/devel ___ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel