Changeset 16d6e42 in rtems


Ignore:
Timestamp:
Jun 19, 2012, 6:34:37 AM (7 years ago)
Author:
Daniel Hellstrom <daniel@…>
Branches:
4.11, master
Children:
0f49c0e
Parents:
f00fee8e
git-author:
Daniel Hellstrom <daniel@…> (06/19/12 06:34:37)
git-committer:
Daniel Hellstrom <daniel@…> (04/16/15 23:10:18)
Message:

LEON3: fixed nano seconds support in TLIB

The _Watchdog_Nanoseconds_since_tick_handler() function caller does
not take into account that the timer counter may wrap, underflow or
overflow. Instead, the driver must take that into account. This
GPTIMER DrvMgr? driver patch makes use of the IRQ-Pending bit to
determine if a underflow has happened. In that case a greater time
than one tick is returned (even considering the function name..).

The TLIB clock layer must also ACK the interrupt pending bit,
otherwise we couldn't determine whether an IRQ is pending or if
belongs to un old already handled tick IRQ.

Note that this patch only fixes the DrvMgr? GPTIMER driver and TLIB,
the standard LEON3 GPTIMER driver still needs a fix.

Location:
c/src/lib/libbsp/sparc/shared
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • c/src/lib/libbsp/sparc/shared/include/tlib.h

    rf00fee8e r16d6e42  
    3636        void    (*get_counter)(struct tlib_dev *hand, unsigned int *counter);
    3737        int     (*custom)(struct tlib_dev *hand, int cmd, void *arg);
     38        int     (*int_pend)(struct tlib_dev *hand, int ack);
    3839};
    3940
     
    168169        dev->drv->custom(dev, cmd, arg);
    169170}
     171
     172static inline int tlib_interrupt_pending(void *hand, int ack)
     173{
     174        struct tlib_dev *dev = hand;
     175
     176        return dev->drv->int_pend(dev, ack);
     177}
  • c/src/lib/libbsp/sparc/shared/timer/gptimer.c

    rf00fee8e r16d6e42  
    8585        char index; /* Timer Index in this driver */
    8686        char tindex; /* Timer Index In Hardware */
     87        unsigned char irq_ack_mask;
    8788};
    8889
     
    275276                timer->tdev.drv = &gptimer_tlib_drv;
    276277
    277                 /* Stop Timer */
    278                 timer->tregs->ctrl = 0;
     278                /* Stop Timer and probe Pending bit. In newer hardware the
     279                 * timer has pending bit is cleared by writing a one to it,
     280                 * whereas older versions it is cleared with a zero.
     281                 */
     282                timer->tregs->ctrl = GPTIMER_CTRL_IP;
     283                if ((timer->tregs->ctrl & GPTIMER_CTRL_IP) != 0)
     284                        timer->irq_ack_mask = ~GPTIMER_CTRL_IP;
     285                else
     286                        timer->irq_ack_mask = ~0;
    279287
    280288                /* Register Timer at Timer Library */
     
    301309                        priv);
    302310        }
     311
     312        /* Older HW */
     313       
     314       
    303315
    304316        /* If the user request a certain Timer to be the RTEMS Clock Timer,
     
    365377}
    366378
     379int gptimer_tlib_int_pend(struct tlib_dev *hand, int ack)
     380{
     381        struct gptimer_timer *timer = (struct gptimer_timer *)hand;
     382        unsigned int ctrl = timer->tregs->ctrl;
     383
     384        if ((ctrl & (GPTIMER_CTRL_IP | GPTIMER_CTRL_IE)) ==
     385                (GPTIMER_CTRL_IP | GPTIMER_CTRL_IE)) {
     386                /* clear Pending IRQ ? */
     387                if (ack)
     388                        timer->tregs->ctrl = ctrl & timer->irq_ack_mask;
     389                return 1; /* timer generated IRQ */
     390        } else
     391                return 0; /* was not timer causing IRQ */
     392}
     393
    367394void gptimer_isr(void *data)
    368395{
    369396        struct gptimer_priv *priv = data;
    370         struct gptimer_timer_regs *tregs;
    371397        int i;
    372         unsigned int ctrl;
    373398
    374399        /* Check all timers for IRQ */
    375400        for (i=0;i<priv->timer_cnt; i++) {
    376                 tregs = priv->timers[i].tregs;
    377                 ctrl = tregs->ctrl;
    378                 if ( ctrl & GPTIMER_CTRL_IP ) {
    379                         /* IRQ Was generated by Timer, Clear Pending flag
    380                          * call ISR registered
     401                if (gptimer_tlib_int_pend((void *)&priv->timers[i], 1)) {
     402                        /* IRQ Was generated by Timer and Pending flag has been
     403                         * cleared. Call ISR registered
    381404                         */
    382                         tregs->ctrl = ctrl | GPTIMER_CTRL_IP;
    383                         if ( priv->timers[i].tdev.isr_func ) {
     405                        if (priv->timers[i].tdev.isr_func) {
    384406                                priv->timers[i].tdev.isr_func(
    385407                                        priv->timers[i].tdev.isr_data);
     
    501523        .get_counter = gptimer_tlib_get_counter,
    502524        .custom = NULL,
     525        .int_pend = gptimer_tlib_int_pend,
    503526};
  • c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c

    rf00fee8e r16d6e42  
    7676{
    7777  /*
     78   * Support for shared interrupts. Ack IRQ at source, only handle
     79   * interrupts generated from the tick-timer. Clearing pending bit
     80   * is also needed for Clock_nanoseconds_since_last_tick() to work.
     81   */
     82  if ( tlib_interrupt_pending(Clock_handle, 1) == 0 )
     83    return;
     84
     85  /*
    7886   *  Accurate count of ISRs
    7987   */
     
    148156{
    149157  uint32_t clicks;
     158  int ip;
     159
    150160  if ( !Clock_handle )
    151161    return 0;
    152162
    153163  tlib_get_counter(Clock_handle, (unsigned int *)&clicks);
     164  /* protect against timer counter underflow/overflow */
     165  ip = tlib_interrupt_pending(Clock_handle, 0);
     166  if (ip)
     167    tlib_get_counter(Clock_handle, (unsigned int *)&clicks);
    154168
    155169#ifdef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
     
    157171    /* Down counter. Calc from BaseFreq. */
    158172    uint64_t tmp;
     173    if (ip)
     174      clicks += Clock_basefreq;
    159175    tmp = ((uint64_t)clicks * 1000000000) / ((uint64_t)Clock_basefreq);
    160176    return (uint32_t)tmp;
     
    163179  /* Down counter. Timer base frequency is initialized to 1 MHz */
    164180  return (uint32_t)
    165      (rtems_configuration_get_microseconds_per_tick() - clicks) * 1000;
     181     ((rtems_configuration_get_microseconds_per_tick() << ip) - clicks) * 1000;
    166182#endif
    167183}
Note: See TracChangeset for help on using the changeset viewer.